source: functions.c @ c453ada

barnowl_perlaim
Last change on this file since c453ada was c453ada, checked in by Geoffrey Thomas <geofft@mit.edu>, 17 years ago
Remove aim.c. buddylist.c, buddy.c, libfaim, and everything that uses them.
  • Property mode set to 100644
File size: 92.6 KB
Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <signal.h>
5#include <netinet/in.h>
6#include <string.h>
7#include <time.h>
8#include <sys/types.h>
9#include <sys/stat.h>
10#include <sys/wait.h>
11#include <errno.h>
12#include <signal.h>
13#include "owl.h"
14
15static const char fileIdent[] = "$Id$";
16
17void owl_function_noop(void)
18{
19  return;
20}
21
22char *owl_function_command(char *cmdbuff)
23{
24  owl_function_debugmsg("executing command: %s", cmdbuff);
25  return owl_cmddict_execute(owl_global_get_cmddict(&g), 
26                             owl_global_get_context(&g), cmdbuff);
27}
28
29void owl_function_command_norv(char *cmdbuff)
30{
31  char *rv;
32  rv=owl_function_command(cmdbuff);
33  if (rv) owl_free(rv);
34}
35
36void owl_function_command_alias(char *alias_from, char *alias_to)
37{
38  owl_cmddict_add_alias(owl_global_get_cmddict(&g), alias_from, alias_to);
39}
40
41owl_cmd *owl_function_get_cmd(char *name)
42{
43  return owl_cmddict_find(owl_global_get_cmddict(&g), name);
44}
45
46void owl_function_show_commands()
47{
48  owl_list l;
49  owl_fmtext fm;
50
51  owl_fmtext_init_null(&fm);
52  owl_fmtext_append_bold(&fm, "Commands:  ");
53  owl_fmtext_append_normal(&fm, "(use 'show command <name>' for details)\n");
54  owl_cmddict_get_names(owl_global_get_cmddict(&g), &l);
55  owl_fmtext_append_list(&fm, &l, "\n", owl_function_cmd_describe);
56  owl_fmtext_append_normal(&fm, "\n");
57  owl_function_popless_fmtext(&fm);
58  owl_cmddict_namelist_free(&l);
59  owl_fmtext_free(&fm);
60}
61
62void owl_function_show_view(char *viewname)
63{
64  owl_view *v;
65  owl_fmtext fm;
66
67  /* we only have the one view right now */
68  v=owl_global_get_current_view(&g);
69  if (viewname && strcmp(viewname, owl_view_get_name(v))) {
70    owl_function_error("No view named '%s'", viewname);
71    return;
72  }
73
74  owl_fmtext_init_null(&fm);
75  owl_view_to_fmtext(v, &fm);
76  owl_function_popless_fmtext(&fm);
77  owl_fmtext_free(&fm);
78}
79
80void owl_function_show_styles() {
81  owl_list l;
82  owl_fmtext fm;
83
84  owl_fmtext_init_null(&fm);
85  owl_fmtext_append_bold(&fm, "Styles:\n");
86  owl_global_get_style_names(&g, &l);
87  owl_fmtext_append_list(&fm, &l, "\n", owl_function_style_describe);
88  owl_fmtext_append_normal(&fm, "\n");
89  owl_function_popless_fmtext(&fm);
90  owl_list_free_all(&l, owl_free);
91  owl_fmtext_free(&fm);
92}
93
94char *owl_function_style_describe(void *name) {
95  char *desc, *s;
96  owl_style *style;
97  style = owl_global_get_style_by_name(&g, name);
98  if (style) {
99    desc = owl_style_get_description(style);
100  } else {
101    desc = "???";
102  }
103  s = owl_sprintf("%-20s - %s%s", name, 
104                  0==owl_style_validate(style)?"":"[INVALID] ",
105                  desc);
106  return s;
107}
108
109char *owl_function_cmd_describe(void *name)
110{
111  owl_cmd *cmd = owl_cmddict_find(owl_global_get_cmddict(&g), name);
112  if (cmd) return owl_cmd_describe(cmd);
113  else return(NULL);
114}
115
116void owl_function_show_command(char *name)
117{
118  owl_function_help_for_command(name);
119}
120
121void owl_function_show_license()
122{
123  char *text;
124
125  text=""
126    "barnowl version " OWL_VERSION_STRING "\n"
127    "Copyright (c) 2006-2008 The BarnOwl Developers. All rights reserved.\n"
128    "Copyright (c) 2004 James Kretchmar. All rights reserved.\n"
129    "\n"
130    "Redistribution and use in source and binary forms, with or without\n"
131    "modification, are permitted provided that the following conditions are\n"
132    "met:\n"
133    "\n"
134    "   * Redistributions of source code must retain the above copyright\n"
135    "     notice, this list of conditions and the following disclaimer.\n"
136    "\n"
137    "   * Redistributions in binary form must reproduce the above copyright\n"
138    "     notice, this list of conditions and the following disclaimer in\n"
139    "     the documentation and/or other materials provided with the\n"
140    "     distribution.\n"
141    "\n"
142    "   * Redistributions in any form must be accompanied by information on\n"
143    "     how to obtain complete source code for the Owl software and any\n"
144    "     accompanying software that uses the Owl software. The source code\n"
145    "     must either be included in the distribution or be available for no\n"
146    "     more than the cost of distribution plus a nominal fee, and must be\n"
147    "     freely redistributable under reasonable conditions. For an\n"
148    "     executable file, complete source code means the source code for\n"
149    "     all modules it contains. It does not include source code for\n"
150    "     modules or files that typically accompany the major components of\n"
151    "     the operating system on which the executable file runs.\n"
152    "\n"
153    "THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n"
154    "IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n"
155    "WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR\n"
156    "NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE\n"
157    "LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n"
158    "CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n"
159    "SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR\n"
160    "BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n"
161    "WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n"
162    "OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n"
163    "IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n";
164  owl_function_popless_text(text);
165}
166
167/* Create an admin message, append it to the global list of messages
168 * and redisplay if necessary.
169 */
170void owl_function_adminmsg(char *header, char *body)
171{
172  owl_message *m;
173
174  m=owl_malloc(sizeof(owl_message));
175  owl_message_create_admin(m, header, body);
176 
177  /* add it to the global list and current view */
178  owl_messagelist_append_element(owl_global_get_msglist(&g), m);
179  owl_view_consider_message(owl_global_get_current_view(&g), m);
180
181  /* do followlast if necessary */
182  if (owl_global_should_followlast(&g)) owl_function_lastmsg_noredisplay();
183
184  /* redisplay etc. */
185  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
186  if (owl_popwin_is_active(owl_global_get_popwin(&g))) {
187    owl_popwin_refresh(owl_global_get_popwin(&g));
188  }
189  wnoutrefresh(owl_global_get_curs_recwin(&g));
190  owl_global_set_needrefresh(&g);
191}
192
193/* Create an outgoing zephyr message and return a pointer to it.  Does
194 * not put it on the global queue, use owl_function_add_message() for
195 * that.
196 */
197owl_message *owl_function_make_outgoing_zephyr(char *body, char *zwriteline, char *zsig)
198{
199  owl_message *m;
200  owl_zwrite z;
201 
202  /* create a zwrite for the purpose of filling in other message fields */
203  owl_zwrite_create_from_line(&z, zwriteline);
204
205  /* create the message */
206  m=owl_malloc(sizeof(owl_message));
207  owl_message_create_from_zwriteline(m, zwriteline, body, zsig);
208  owl_zwrite_free(&z);
209
210  return(m);
211}
212
213/* Create an outgoing loopback message and return a pointer to it.
214 * Does not append it to the global queue, use
215 * owl_function_add_message() for that.
216 */
217owl_message *owl_function_make_outgoing_loopback(char *body)
218{
219  owl_message *m;
220
221  /* create the message */
222  m=owl_malloc(sizeof(owl_message));
223  owl_message_create_loopback(m, body);
224  owl_message_set_direction_out(m);
225
226  return(m);
227}
228
229void owl_function_zwrite_setup(char *line)
230{
231  owl_editwin *e;
232  char buff[1024];
233  owl_zwrite z;
234  int ret;
235
236  /* check the arguments */
237  ret=owl_zwrite_create_from_line(&z, line);
238  if (ret) {
239    owl_function_error("Error in zwrite arguments");
240    owl_zwrite_free(&z);
241    return;
242  }
243
244  /* send a ping if necessary */
245  if (owl_global_is_txping(&g)) {
246    owl_zwrite_send_ping(&z);
247  }
248  owl_zwrite_free(&z);
249
250  /* create and setup the editwin */
251  e=owl_global_get_typwin(&g);
252  owl_editwin_new_style(e, OWL_EDITWIN_STYLE_MULTILINE, owl_global_get_msg_history(&g));
253
254  if (!owl_global_get_lockout_ctrld(&g)) {
255    owl_function_makemsg("Type your zephyr below.  End with ^D or a dot on a line by itself.  ^C will quit.");
256  } else {
257    owl_function_makemsg("Type your zephyr below.  End with a dot on a line by itself.  ^C will quit.");
258  }
259
260  owl_editwin_clear(e);
261  owl_editwin_set_dotsend(e);
262  strcpy(buff, "----> ");
263  strcat(buff, line);
264  strcat(buff, "\n");
265  owl_editwin_set_locktext(e, buff);
266
267  /* make it active */
268  owl_global_set_typwin_active(&g);
269
270  owl_global_set_buffercommand(&g, line);
271  owl_global_set_buffercallback(&g, &owl_callback_zwrite);
272}
273
274void owl_function_loopwrite_setup()
275{
276  owl_editwin *e;
277
278  /* create and setup the editwin */
279  e=owl_global_get_typwin(&g);
280  owl_editwin_new_style(e, OWL_EDITWIN_STYLE_MULTILINE, owl_global_get_msg_history(&g));
281
282  if (!owl_global_get_lockout_ctrld(&g)) {
283    owl_function_makemsg("Type your message below.  End with ^D or a dot on a line by itself.  ^C will quit.");
284  } else {
285    owl_function_makemsg("Type your message below.  End with a dot on a line by itself.  ^C will quit.");
286  }
287
288  owl_editwin_clear(e);
289  owl_editwin_set_dotsend(e);
290  owl_editwin_set_locktext(e, "----> loopwrite\n");
291
292  /* make it active */
293  owl_global_set_typwin_active(&g);
294
295  owl_global_set_buffercommand(&g, "loopwrite");
296  owl_global_set_buffercallback(&g, &owl_callback_loopwrite);
297}
298
299void owl_callback_zwrite(owl_editwin *e) {
300  owl_function_zwrite(owl_editwin_get_command(e),
301                      owl_editwin_get_text(e));
302}
303
304/* send, log and display an outgoing zephyr.  If 'msg' is NULL
305 * the message is expected to be set from the zwrite line itself
306 */
307void owl_function_zwrite(char *line, char *msg)
308{
309  owl_zwrite z;
310  char *mymsg;
311  owl_message *m;
312
313  if(!strncmp(line, "zcrypt", strlen("zcrypt"))) {
314    owl_function_zcrypt(line, msg);
315    return;
316  }
317
318  /* create the zwrite and send the message */
319  owl_zwrite_create_from_line(&z, line);
320  if (msg) {
321    owl_zwrite_set_message(&z, msg);
322  }
323  owl_zwrite_send_message(&z);
324  owl_function_makemsg("Waiting for ack...");
325
326  /* If it's personal */
327  if (owl_zwrite_is_personal(&z)) {
328    /* create the outgoing message */
329    mymsg=owl_zwrite_get_message(&z);
330    m=owl_function_make_outgoing_zephyr(mymsg, line, owl_zwrite_get_zsig(&z));
331
332    if (m) {
333      owl_global_messagequeue_addmsg(&g, m);
334    } else {
335      owl_function_error("Could not create outgoing zephyr message");
336    }
337  }
338
339  /* free the zwrite */
340  owl_zwrite_free(&z);
341}
342
343/* send, log and display an outgoing zcrypt zephyr.  If 'msg' is NULL
344 * the message is expected to be set from the zwrite line itself
345 */
346void owl_function_zcrypt(char *line, char *msg)
347{
348  owl_zwrite z;
349  char *mymsg;
350  char *cryptmsg;
351  owl_message *m;
352#ifdef OWL_ENABLE_ZCRYPT
353  int ret;
354#endif
355
356  /* create the zwrite and send the message */
357  owl_zwrite_create_from_line(&z, line);
358  if (msg) {
359    owl_zwrite_set_message(&z, msg);
360  }
361
362  mymsg=owl_zwrite_get_message(&z);
363#ifdef OWL_ENABLE_ZCRYPT
364  cryptmsg=owl_malloc(strlen(mymsg)*4);
365  ret=owl_zcrypt_encrypt(cryptmsg, mymsg, owl_zwrite_get_class(&z), owl_zwrite_get_instance(&z));
366  if (ret) {
367    owl_function_error("Error in zcrypt, possibly no key found.  Message not sent.");
368    owl_function_beep();
369    owl_free(cryptmsg);
370    return;
371  }
372#else
373  cryptmsg=owl_strdup(mymsg);
374#endif
375
376  owl_zwrite_set_message(&z, cryptmsg);
377  owl_zwrite_set_opcode(&z, "crypt");
378  mymsg=cryptmsg;
379   
380  owl_zwrite_send_message(&z);
381  owl_function_makemsg("Waiting for ack...");
382
383  /* If it's personal */
384  if (owl_zwrite_is_personal(&z)) {
385    /* create the outgoing message */
386    mymsg=owl_zwrite_get_message(&z);
387    m=owl_function_make_outgoing_zephyr(mymsg, line, owl_zwrite_get_zsig(&z));
388    if (m) {
389      owl_global_messagequeue_addmsg(&g, m);
390    } else {
391      owl_function_error("Could not create outgoing zephyr message");
392    }
393  }
394
395  /* free the zwrite */
396  owl_free(cryptmsg);
397  owl_zwrite_free(&z);
398}
399
400void owl_callback_loopwrite(owl_editwin *e) {
401  owl_function_loopwrite(owl_editwin_get_text(e));
402}
403
404void owl_function_loopwrite(char *msg)
405{
406  owl_message *min, *mout;
407
408  /* create a message and put it on the message queue.  This simulates
409   * an incoming message */
410  min=owl_malloc(sizeof(owl_message));
411  mout=owl_function_make_outgoing_loopback(msg);
412
413  if (owl_global_is_displayoutgoing(&g)) {
414    owl_global_messagequeue_addmsg(&g, mout);
415  } else {
416    owl_message_free(mout);
417  }
418
419  owl_message_create_loopback(min, msg);
420  owl_message_set_direction_in(min);
421  owl_global_messagequeue_addmsg(&g, min);
422
423  /* fake a makemsg */
424  owl_function_makemsg("loopback message sent");
425}
426
427/* If filter is non-null, looks for the next message matching
428 * that filter.  If skip_deleted, skips any deleted messages.
429 * If last_if_none, will stop at the last message in the view
430 * if no matching messages are found.  */
431void owl_function_nextmsg_full(char *filter, int skip_deleted, int last_if_none)
432{
433  int curmsg, i, viewsize, found;
434  owl_view *v;
435  owl_filter *f = NULL;
436  owl_message *m;
437
438  v=owl_global_get_current_view(&g);
439
440  if (filter) {
441    f=owl_global_get_filter(&g, filter);
442    if (!f) {
443      owl_function_error("No %s filter defined", filter);
444      return;
445    }
446  }
447
448  curmsg=owl_global_get_curmsg(&g);
449  viewsize=owl_view_get_size(v);
450  found=0;
451
452  /* just check to make sure we're in bounds... */
453  if (curmsg>viewsize-1) curmsg=viewsize-1;
454  if (curmsg<0) curmsg=0;
455
456  for (i=curmsg+1; i<viewsize; i++) {
457    m=owl_view_get_element(v, i);
458    if (skip_deleted && owl_message_is_delete(m)) continue;
459    if (f && !owl_filter_message_match(f, m)) continue;
460    found = 1;
461    break;
462  }
463
464  if (i>owl_view_get_size(v)-1) i=owl_view_get_size(v)-1;
465  if (i<0) i=0;
466
467  if (!found) {
468    owl_function_makemsg("already at last%s message%s%s",
469                         skip_deleted?" non-deleted":"",
470                         filter?" in ":"", filter?filter:"");
471    /* if (!skip_deleted) owl_function_beep(); */
472  }
473
474  if (last_if_none || found) {
475    owl_global_set_curmsg(&g, i);
476    owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
477    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
478    owl_global_set_direction_downwards(&g);
479  }
480}
481
482void owl_function_prevmsg_full(char *filter, int skip_deleted, int first_if_none)
483{
484  int curmsg, i, viewsize, found;
485  owl_view *v;
486  owl_filter *f = NULL;
487  owl_message *m;
488
489  v=owl_global_get_current_view(&g);
490
491  if (filter) {
492    f=owl_global_get_filter(&g, filter);
493    if (!f) {
494      owl_function_error("No %s filter defined", filter);
495      return;
496    }
497  }
498
499  curmsg=owl_global_get_curmsg(&g);
500  viewsize=owl_view_get_size(v);
501  found=0;
502
503  /* just check to make sure we're in bounds... */
504  if (curmsg<0) curmsg=0;
505
506  for (i=curmsg-1; i>=0; i--) {
507    m=owl_view_get_element(v, i);
508    if (skip_deleted && owl_message_is_delete(m)) continue;
509    if (f && !owl_filter_message_match(f, m)) continue;
510    found = 1;
511    break;
512  }
513
514  if (i<0) i=0;
515
516  if (!found) {
517    owl_function_makemsg("already at first%s message%s%s",
518                         skip_deleted?" non-deleted":"",
519                         filter?" in ":"", filter?filter:"");
520    /* if (!skip_deleted) owl_function_beep(); */
521  }
522
523  if (first_if_none || found) {
524    owl_global_set_curmsg(&g, i);
525    owl_function_calculate_topmsg(OWL_DIRECTION_UPWARDS);
526    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
527    owl_global_set_direction_upwards(&g);
528  }
529}
530
531void owl_function_nextmsg()
532{
533  owl_function_nextmsg_full(NULL, 0, 1);
534}
535
536void owl_function_prevmsg()
537{
538  owl_function_prevmsg_full(NULL, 0, 1);
539}
540
541void owl_function_nextmsg_notdeleted()
542{
543  owl_function_nextmsg_full(NULL, 1, 1);
544}
545
546void owl_function_prevmsg_notdeleted()
547{
548  owl_function_prevmsg_full(NULL, 1, 1);
549}
550
551void owl_function_nextmsg_personal()
552{
553  owl_function_nextmsg_full("personal", 0, 0);
554}
555
556void owl_function_prevmsg_personal()
557{
558  owl_function_prevmsg_full("personal", 0, 0);
559}
560
561
562/* if move_after is 1, moves after the delete */
563void owl_function_deletecur(int move_after)
564{
565  int curmsg;
566  owl_view *v;
567
568  v=owl_global_get_current_view(&g);
569
570  /* bail if there's no current message */
571  if (owl_view_get_size(v) < 1) {
572    owl_function_error("No current message to delete");
573    return;
574  }
575
576  /* mark the message for deletion */
577  curmsg=owl_global_get_curmsg(&g);
578  owl_view_delete_element(v, curmsg);
579
580  if (move_after) {
581    /* move the poiner in the appropriate direction
582     * to the next undeleted msg */
583    if (owl_global_get_direction(&g)==OWL_DIRECTION_UPWARDS) {
584      owl_function_prevmsg_notdeleted();
585    } else {
586      owl_function_nextmsg_notdeleted();
587    }
588  }
589}
590
591void owl_function_undeletecur(int move_after)
592{
593  int curmsg;
594  owl_view *v;
595
596  v=owl_global_get_current_view(&g);
597 
598  if (owl_view_get_size(v) < 1) {
599    owl_function_error("No current message to undelete");
600    return;
601  }
602  curmsg=owl_global_get_curmsg(&g);
603
604  owl_view_undelete_element(v, curmsg);
605
606  if (move_after) {
607    if (owl_global_get_direction(&g)==OWL_DIRECTION_UPWARDS) {
608      if (curmsg>0) {
609        owl_function_prevmsg();
610      } else {
611        owl_function_nextmsg();
612      }
613    } else {
614      owl_function_nextmsg();
615    }
616  }
617
618  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
619}
620
621void owl_function_expunge()
622{
623  int curmsg;
624  owl_message *m;
625  owl_messagelist *ml;
626  owl_view *v;
627  int lastmsgid=0;
628
629  curmsg=owl_global_get_curmsg(&g);
630  v=owl_global_get_current_view(&g);
631  ml=owl_global_get_msglist(&g);
632
633  m=owl_view_get_element(v, curmsg);
634  if (m) lastmsgid = owl_message_get_id(m);
635
636  /* expunge the message list */
637  owl_messagelist_expunge(ml);
638
639  /* update all views (we only have one right now) */
640  owl_view_recalculate(v);
641
642  /* find where the new position should be
643     (as close as possible to where we last where) */
644  curmsg = owl_view_get_nearest_to_msgid(v, lastmsgid);
645  if (curmsg>owl_view_get_size(v)-1) curmsg = owl_view_get_size(v)-1;
646  if (curmsg<0) curmsg = 0;
647  owl_global_set_curmsg(&g, curmsg);
648  owl_function_calculate_topmsg(OWL_DIRECTION_NONE);
649  /* if there are no messages set the direction to down in case we
650     delete everything upwards */
651  owl_global_set_direction_downwards(&g);
652 
653  owl_function_makemsg("Messages expunged");
654  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
655}
656
657void owl_function_firstmsg()
658{
659  owl_global_set_curmsg(&g, 0);
660  owl_global_set_topmsg(&g, 0);
661  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
662  owl_global_set_direction_downwards(&g);
663}
664
665void owl_function_lastmsg_noredisplay()
666{
667  int oldcurmsg, curmsg;
668  owl_view *v;
669
670  v=owl_global_get_current_view(&g);
671  oldcurmsg=owl_global_get_curmsg(&g);
672  curmsg=owl_view_get_size(v)-1; 
673  if (curmsg<0) curmsg=0;
674  owl_global_set_curmsg(&g, curmsg);
675  if (oldcurmsg < curmsg) {
676    owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
677  } else if (curmsg<owl_view_get_size(v)) {
678    /* If already at the end, blank the screen and move curmsg
679     * past the end of the messages. */
680    owl_global_set_topmsg(&g, curmsg+1);
681    owl_global_set_curmsg(&g, curmsg+1);
682  } 
683  /* owl_mainwin_redisplay(owl_global_get_mainwin(&g)); */
684  owl_global_set_direction_downwards(&g);
685}
686
687void owl_function_lastmsg()
688{
689  owl_function_lastmsg_noredisplay();
690  owl_mainwin_redisplay(owl_global_get_mainwin(&g)); 
691}
692
693void owl_function_shift_right()
694{
695  owl_global_set_rightshift(&g, owl_global_get_rightshift(&g)+10);
696  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
697  owl_global_set_needrefresh(&g);
698}
699
700void owl_function_shift_left()
701{
702  int shift;
703
704  shift=owl_global_get_rightshift(&g);
705  if (shift>=10) {
706    owl_global_set_rightshift(&g, shift-10);
707    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
708    owl_global_set_needrefresh(&g);
709  } else {
710    owl_function_beep();
711    owl_function_makemsg("Already full left");
712  }
713}
714
715void owl_function_unsuball()
716{
717  unsuball();
718  owl_function_makemsg("Unsubscribed from all messages.");
719}
720
721
722/* Load zephyr subscriptions from the named 'file' and load zephyr's
723 * default subscriptions as well.  An error message is printed if
724 * 'file' can't be opened or if zephyr reports an error in
725 * subscribing.
726 *
727 * If 'file' is NULL, this look for the default filename
728 * $HOME/.zephyr.subs.  If the file can not be opened in this case
729 * only, no error message is printed.
730 */
731void owl_function_loadsubs(char *file)
732{
733  int ret, ret2;
734  char *foo, *path;
735
736  if (file==NULL) {
737    ret=owl_zephyr_loadsubs(NULL, 0);
738  } else {
739    path = owl_util_makepath(file);
740    ret=owl_zephyr_loadsubs(path, 1);
741    free(path);
742  }
743
744  /* for backwards compatibility for now */
745  ret2=owl_zephyr_loaddefaultsubs();
746
747  if (!owl_context_is_interactive(owl_global_get_context(&g))) return;
748
749  foo=file?file:"file";
750  if (ret==0 && ret2==0) {
751    if (!file) {
752      owl_function_makemsg("Subscribed to messages.");
753    } else {
754      owl_function_makemsg("Subscribed to messages from %s", file);
755    }
756  } else if (ret==-1) {
757    owl_function_error("Could not read %s", foo);
758  } else {
759    owl_function_error("Error subscribing to messages");
760  }
761}
762
763void owl_function_loadloginsubs(char *file)
764{
765  int ret;
766
767  ret=owl_zephyr_loadloginsubs(file);
768
769  if (!owl_context_is_interactive(owl_global_get_context(&g))) return;
770  if (ret==0) {
771    owl_function_makemsg("Subscribed to login messages from file.");
772  } else if (ret==-1) {
773    owl_function_error("Could not open file for login subscriptions.");
774  } else {
775    owl_function_error("Error subscribing to login messages from file.");
776  }
777}
778
779void owl_function_suspend()
780{
781  endwin();
782  printf("\n");
783  kill(getpid(), SIGSTOP);
784
785  /* resize to reinitialize all the windows when we come back */
786  owl_command_resize();
787}
788
789void owl_function_zaway_toggle()
790{
791  if (!owl_global_is_zaway(&g)) {
792    owl_global_set_zaway_msg(&g, owl_global_get_zaway_msg_default(&g));
793    owl_function_zaway_on();
794  } else {
795    owl_function_zaway_off();
796  }
797}
798
799void owl_function_zaway_on()
800{
801  owl_global_set_zaway_on(&g);
802  owl_function_makemsg("zaway set (%s)", owl_global_get_zaway_msg(&g));
803}
804
805void owl_function_zaway_off()
806{
807  owl_global_set_zaway_off(&g);
808  owl_function_makemsg("zaway off");
809}
810
811void owl_function_quit()
812{
813  char *ret;
814 
815  /* zlog out if we need to */
816  if (owl_global_is_shutdownlogout(&g)) {
817    owl_zephyr_zlog_out();
818  }
819
820  /* execute the commands in shutdown */
821  ret = owl_perlconfig_execute("BarnOwl::Hooks::_shutdown();");
822  if (ret) owl_free(ret);
823
824  /* signal our child process, if any */
825  if (owl_global_get_newmsgproc_pid(&g)) {
826    kill(owl_global_get_newmsgproc_pid(&g), SIGHUP);
827  }
828
829  /* Quit zephyr */
830  owl_zephyr_shutdown();
831 
832  /* done with curses */
833  endwin();
834
835  /* restore terminal settings */
836  tcsetattr(0, TCSAFLUSH, owl_global_get_startup_tio(&g));
837
838  owl_function_debugmsg("Quitting Owl");
839  exit(0);
840}
841
842void owl_function_openurl()
843{
844  /* visit the first url in the current message */
845  owl_message *m;
846  owl_view *v;
847  char *ptr1, *ptr2, *text, url[LINE], tmpbuff[LINE];
848  int webbrowser;
849
850  webbrowser = owl_global_get_webbrowser(&g);
851
852  if (webbrowser < 0 || webbrowser == OWL_WEBBROWSER_NONE) {
853    owl_function_error("No browser selected");
854    return;
855  }
856
857  v=owl_global_get_current_view(&g);
858 
859  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
860
861  if (!m || owl_view_get_size(v)==0) {
862    owl_function_error("No current message selected");
863    return;
864  }
865
866  text=owl_message_get_text(m);
867
868  /* First look for a good URL */ 
869  if ((ptr1=strstr(text, "http://"))!=NULL) {
870    ptr2=strpbrk(ptr1, " \n\t");
871    if (ptr2) {
872      strncpy(url, ptr1, ptr2-ptr1+1);
873      url[ptr2-ptr1+1]='\0';
874    } else {
875      strcpy(url, ptr1);
876    }
877
878    /* if we had <http strip a trailing > */
879    if (ptr1>text && ptr1[-1]=='<') {
880      if (url[strlen(url)-1]=='>') {
881        url[strlen(url)-1]='\0';
882      }
883    }
884  } else if ((ptr1=strstr(text, "https://"))!=NULL) {
885    /* Look for an https URL */ 
886    ptr2=strpbrk(ptr1, " \n\t");
887    if (ptr2) {
888      strncpy(url, ptr1, ptr2-ptr1+1);
889      url[ptr2-ptr1+1]='\0';
890    } else {
891      strcpy(url, ptr1);
892    }
893   
894    /* if we had <http strip a trailing > */
895    if (ptr1>text && ptr1[-1]=='<') {
896      if (url[strlen(url)-1]=='>') {
897        url[strlen(url)-1]='\0';
898      }
899    }
900  } else if ((ptr1=strstr(text, "www."))!=NULL) {
901    /* if we can't find a real url look for www.something */
902    ptr2=strpbrk(ptr1, " \n\t");
903    if (ptr2) {
904      strncpy(url, ptr1, ptr2-ptr1+1);
905      url[ptr2-ptr1+1]='\0';
906    } else {
907      strcpy(url, ptr1);
908    }
909  } else {
910    owl_function_beep();
911    owl_function_error("Could not find URL to open.");
912    return;
913  }
914
915  /* Make sure there aren't any quotes or \'s in the url */
916  for (ptr1 = url; *ptr1; ptr1++) {
917    if (*ptr1 == '"' || *ptr1 == '\\') {
918      owl_function_beep();
919      owl_function_error("URL contains invalid characters.");
920      return;
921    }
922  }
923 
924  /* NOTE: There are potentially serious security issues here... */
925
926  /* open the page */
927  owl_function_makemsg("Opening %s", url);
928  if (webbrowser == OWL_WEBBROWSER_NETSCAPE) {
929    snprintf(tmpbuff, LINE, "netscape -remote \"openURL(%s)\" > /dev/null 2> /dev/null", url);
930    system(tmpbuff); 
931  } else if (webbrowser == OWL_WEBBROWSER_GALEON) {
932    snprintf(tmpbuff, LINE, "galeon \"%s\" > /dev/null 2> /dev/null &", url);
933    system(tmpbuff); 
934  } else if (webbrowser == OWL_WEBBROWSER_OPERA) {
935    snprintf(tmpbuff, LINE, "opera \"%s\" > /dev/null 2> /dev/null &", url);
936    system(tmpbuff); 
937  }
938}
939
940void owl_function_calculate_topmsg(int direction)
941{
942  int recwinlines, topmsg, curmsg;
943  owl_view *v;
944
945  v=owl_global_get_current_view(&g);
946  curmsg=owl_global_get_curmsg(&g);
947  topmsg=owl_global_get_topmsg(&g);
948  recwinlines=owl_global_get_recwin_lines(&g);
949
950  /*
951  if (owl_view_get_size(v) < 1) {
952    return;
953  }
954  */
955
956  switch (owl_global_get_scrollmode(&g)) {
957  case OWL_SCROLLMODE_TOP:
958    topmsg = owl_function_calculate_topmsg_top(direction, v, curmsg, topmsg, recwinlines);
959    break;
960  case OWL_SCROLLMODE_NEARTOP:
961    topmsg = owl_function_calculate_topmsg_neartop(direction, v, curmsg, topmsg, recwinlines);
962    break;
963  case OWL_SCROLLMODE_CENTER:
964    topmsg = owl_function_calculate_topmsg_center(direction, v, curmsg, topmsg, recwinlines);
965    break;
966  case OWL_SCROLLMODE_PAGED:
967    topmsg = owl_function_calculate_topmsg_paged(direction, v, curmsg, topmsg, recwinlines, 0);
968    break;
969  case OWL_SCROLLMODE_PAGEDCENTER:
970    topmsg = owl_function_calculate_topmsg_paged(direction, v, curmsg, topmsg, recwinlines, 1);
971    break;
972  case OWL_SCROLLMODE_NORMAL:
973  default:
974    topmsg = owl_function_calculate_topmsg_normal(direction, v, curmsg, topmsg, recwinlines);
975  }
976  owl_function_debugmsg("Calculated a topmsg of %i", topmsg);
977  owl_global_set_topmsg(&g, topmsg);
978}
979
980/* Returns what the new topmsg should be. 
981 * Passed the last direction of movement,
982 * the current view,
983 * the current message number in the view,
984 * the top message currently being displayed,
985 * and the number of lines in the recwin.
986 */
987int owl_function_calculate_topmsg_top(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines)
988{
989  return(curmsg);
990}
991
992int owl_function_calculate_topmsg_neartop(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines)
993{
994  if (curmsg>0 
995      && (owl_message_get_numlines(owl_view_get_element(v, curmsg-1))
996          <  recwinlines/2)) {
997    return(curmsg-1);
998  } else {
999    return(curmsg);
1000  }
1001}
1002 
1003int owl_function_calculate_topmsg_center(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines)
1004{
1005  int i, last, lines;
1006
1007  last = curmsg;
1008  lines = 0;
1009  for (i=curmsg-1; i>=0; i--) {
1010    lines += owl_message_get_numlines(owl_view_get_element(v, i));
1011    if (lines > recwinlines/2) break;
1012    last = i;
1013  }
1014  return(last);
1015}
1016 
1017int owl_function_calculate_topmsg_paged(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines, int center_on_page)
1018{
1019  int i, last, lines, savey;
1020 
1021  /* If we're off the top of the screen, scroll up such that the
1022   * curmsg is near the botton of the screen. */
1023  if (curmsg < topmsg) {
1024    last = curmsg;
1025    lines = 0;
1026    for (i=curmsg; i>=0; i--) {
1027      lines += owl_message_get_numlines(owl_view_get_element(v, i));
1028      if (lines > recwinlines) break;
1029    last = i;
1030    }
1031    if (center_on_page) {
1032      return(owl_function_calculate_topmsg_center(direction, v, curmsg, 0, recwinlines));
1033    } else {
1034      return(last);
1035    }
1036  }
1037
1038  /* Find number of lines from top to bottom of curmsg (store in savey) */
1039  savey=0;
1040  for (i=topmsg; i<=curmsg; i++) {
1041    savey+=owl_message_get_numlines(owl_view_get_element(v, i));
1042  }
1043
1044  /* if we're off the bottom of the screen, scroll down */
1045  if (savey > recwinlines) {
1046    if (center_on_page) {
1047      return(owl_function_calculate_topmsg_center(direction, v, curmsg, 0, recwinlines));
1048    } else {
1049      return(curmsg);
1050    }
1051  }
1052
1053  /* else just stay as we are... */
1054  return(topmsg);
1055}
1056
1057int owl_function_calculate_topmsg_normal(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines)
1058{
1059  int savey, i, foo, y;
1060
1061  if (curmsg<0) return(topmsg);
1062   
1063  /* If we're off the top of the screen then center */
1064  if (curmsg<topmsg) {
1065    topmsg=owl_function_calculate_topmsg_center(direction, v, curmsg, 0, recwinlines);
1066  }
1067
1068  /* If curmsg is so far past topmsg that there are more messages than
1069     lines, skip the line counting that follows because we're
1070     certainly off screen.  */
1071  savey=curmsg-topmsg;
1072  if (savey <= recwinlines) {
1073    /* Find number of lines from top to bottom of curmsg (store in savey) */
1074    savey = 0;
1075    for (i=topmsg; i<=curmsg; i++) {
1076      savey+=owl_message_get_numlines(owl_view_get_element(v, i));
1077    }
1078  }
1079
1080  /* If we're off the bottom of the screen, set the topmsg to curmsg
1081   * and scroll upwards */
1082  if (savey > recwinlines) {
1083    topmsg=curmsg;
1084    savey=owl_message_get_numlines(owl_view_get_element(v, curmsg));
1085    direction=OWL_DIRECTION_UPWARDS;
1086  }
1087 
1088  /* If our bottom line is less than 1/4 down the screen then scroll up */
1089  if (direction == OWL_DIRECTION_UPWARDS || direction == OWL_DIRECTION_NONE) {
1090    if (savey < (recwinlines / 4)) {
1091      y=0;
1092      for (i=curmsg; i>=0; i--) {
1093        foo=owl_message_get_numlines(owl_view_get_element(v, i));
1094        /* will we run the curmsg off the screen? */
1095        if ((foo+y) >= recwinlines) {
1096          i++;
1097          if (i>curmsg) i=curmsg;
1098          break;
1099        }
1100        /* have saved 1/2 the screen space? */
1101        y+=foo;
1102        if (y > (recwinlines / 2)) break;
1103      }
1104      if (i<0) i=0;
1105      return(i);
1106    }
1107  }
1108
1109  if (direction == OWL_DIRECTION_DOWNWARDS || direction == OWL_DIRECTION_NONE) {
1110    /* If curmsg bottom line is more than 3/4 down the screen then scroll down */
1111    if (savey > ((recwinlines * 3)/4)) {
1112      y=0;
1113      /* count lines from the top until we can save 1/2 the screen size */
1114      for (i=topmsg; i<curmsg; i++) {
1115        y+=owl_message_get_numlines(owl_view_get_element(v, i));
1116        if (y > (recwinlines / 2)) break;
1117      }
1118      if (i==curmsg) {
1119        i--;
1120      }
1121      return(i+1);
1122    }
1123  }
1124
1125  return(topmsg);
1126}
1127
1128void owl_function_resize()
1129{
1130  owl_global_set_resize_pending(&g);
1131}
1132
1133void owl_function_run_buffercommand()
1134{
1135  owl_editwin_do_callback(owl_global_get_typwin(&g));
1136}
1137
1138void owl_function_debugmsg(char *fmt, ...)
1139{
1140  FILE *file;
1141  time_t now;
1142  char buff1[LINE], buff2[LINE];
1143  va_list ap;
1144  va_start(ap, fmt);
1145
1146  if (!owl_global_is_debug_fast(&g)) return;
1147
1148  file=fopen(owl_global_get_debug_file(&g), "a");
1149  if (!file) return;
1150
1151  now=time(NULL);
1152  strcpy(buff1, ctime(&now));
1153  buff1[strlen(buff1)-1]='\0';
1154
1155  owl_global_get_runtime_string(&g, buff2);
1156 
1157  fprintf(file, "[%i -  %s - %s]: ", (int) getpid(), buff1, buff2);
1158  vfprintf(file, fmt, ap);
1159  fprintf(file, "\n");
1160  fclose(file);
1161
1162  va_end(ap);
1163}
1164
1165void owl_function_refresh()
1166{
1167  owl_function_resize();
1168}
1169
1170void owl_function_beep()
1171{
1172  if (owl_global_is_bell(&g)) {
1173    beep();
1174    owl_global_set_needrefresh(&g); /* do we really need this? */
1175  }
1176}
1177
1178int owl_function_subscribe(char *class, char *inst, char *recip)
1179{
1180  int ret;
1181
1182  ret=owl_zephyr_sub(class, inst, recip);
1183  if (ret) {
1184    owl_function_error("Error subscribing.");
1185  } else {
1186    owl_function_makemsg("Subscribed.");
1187  }
1188  return(ret);
1189}
1190
1191void owl_function_unsubscribe(char *class, char *inst, char *recip)
1192{
1193  int ret;
1194
1195  ret=owl_zephyr_unsub(class, inst, recip);
1196  if (ret) {
1197    owl_function_error("Error subscribing.");
1198  } else {
1199    owl_function_makemsg("Unsubscribed.");
1200  }
1201}
1202
1203void owl_function_set_cursor(WINDOW *win)
1204{
1205  wnoutrefresh(win);
1206}
1207
1208void owl_function_full_redisplay()
1209{
1210  redrawwin(owl_global_get_curs_recwin(&g));
1211  redrawwin(owl_global_get_curs_sepwin(&g));
1212  /* Work around curses segfualts with windows off the screen */
1213  if (g.lines >= owl_global_get_typwin_lines(&g)+2)
1214      redrawwin(owl_global_get_curs_typwin(&g));
1215  if (g.lines >= 2)
1216      redrawwin(owl_global_get_curs_msgwin(&g));
1217
1218  wnoutrefresh(owl_global_get_curs_recwin(&g));
1219  wnoutrefresh(owl_global_get_curs_sepwin(&g));
1220  wnoutrefresh(owl_global_get_curs_typwin(&g));
1221  wnoutrefresh(owl_global_get_curs_msgwin(&g));
1222
1223  if (owl_popwin_is_active(owl_global_get_popwin(&g))) {
1224    owl_popwin_refresh(owl_global_get_popwin(&g));
1225  }
1226 
1227  sepbar("");
1228  owl_function_makemsg("");
1229
1230  owl_global_set_needrefresh(&g);
1231}
1232
1233void owl_function_popless_text(char *text)
1234{
1235  owl_popwin *pw;
1236  owl_viewwin *v;
1237
1238  pw=owl_global_get_popwin(&g);
1239  v=owl_global_get_viewwin(&g);
1240
1241  owl_popwin_up(pw);
1242  owl_viewwin_init_text(v, owl_popwin_get_curswin(pw),
1243                        owl_popwin_get_lines(pw), owl_popwin_get_cols(pw),
1244                        text);
1245  owl_popwin_refresh(pw);
1246  owl_viewwin_redisplay(v, 0);
1247  owl_global_set_needrefresh(&g);
1248}
1249
1250void owl_function_popless_fmtext(owl_fmtext *fm)
1251{
1252  owl_popwin *pw;
1253  owl_viewwin *v;
1254
1255  pw=owl_global_get_popwin(&g);
1256  v=owl_global_get_viewwin(&g);
1257
1258  owl_popwin_up(pw);
1259  owl_viewwin_init_fmtext(v, owl_popwin_get_curswin(pw),
1260                   owl_popwin_get_lines(pw), owl_popwin_get_cols(pw),
1261                   fm);
1262  owl_popwin_refresh(pw);
1263  owl_viewwin_redisplay(v, 0);
1264  owl_global_set_needrefresh(&g);
1265}
1266
1267void owl_function_popless_file(char *filename)
1268{
1269  owl_fmtext fm;
1270  FILE *file;
1271  char buff[1024];
1272
1273  file=fopen(filename, "r");
1274  if (!file) {
1275    owl_function_error("Could not open file: %s", filename);
1276    return;
1277  }
1278
1279  owl_fmtext_init_null(&fm);
1280  while (fgets(buff, 1024, file)) {
1281    owl_fmtext_append_normal(&fm, buff);
1282    /*    owl_fmtext_append_normal(&fm, "\n"); */
1283  }
1284
1285  owl_function_popless_fmtext(&fm);
1286  owl_fmtext_free(&fm);
1287  fclose(file);
1288}
1289
1290void owl_function_about()
1291{
1292  char buff[5000];
1293
1294  sprintf(buff, "This is barnowl version %s\n\n", OWL_VERSION_STRING);
1295  strcat(buff, "barnowl is a fork of the Owl zephyr client, written and\n");
1296  strcat(buff, "maintained by Alejandro Sedeno and Nelson Elhage at the\n");
1297  strcat(buff, "Massachusetts Institute of Technology. \n");
1298  strcat(buff, "\n");
1299  strcat(buff, "Owl was written by James Kretchmar. The first version, 0.5, was\n");
1300  strcat(buff, "released in March 2002.\n");
1301  strcat(buff, "\n");
1302  strcat(buff, "The name 'owl' was chosen in reference to the owls in the\n");
1303  strcat(buff, "Harry Potter novels, who are tasked with carrying messages\n");
1304  strcat(buff, "between Witches and Wizards. The name 'barnowl' was chosen\n");
1305  strcat(buff, "because we feel our owls should live closer to our ponies.\n");
1306  strcat(buff, "\n");
1307  strcat(buff, "Copyright (c) 2006-2008 The BarnOwl Developers. All rights reserved.\n");
1308  strcat(buff, "Copyright (c) 2004 James Kretchmar. All rights reserved.\n");
1309  strcat(buff, "Copyright 2002 Massachusetts Institute of Technology\n");
1310  strcat(buff, "\n");
1311  strcat(buff, "This program is free software. You can redistribute it and/or\n");
1312  strcat(buff,  "modify under the terms of the Sleepycat License. Use the \n");
1313  strcat(buff,  "':show license' command to display the full license\n");
1314  owl_function_popless_text(buff);
1315}
1316
1317void owl_function_info()
1318{
1319  owl_message *m;
1320  owl_fmtext fm, attrfm;
1321  char buff[10000];
1322  owl_view *v;
1323#ifdef HAVE_LIBZEPHYR
1324  ZNotice_t *n;
1325#endif
1326
1327  owl_fmtext_init_null(&fm);
1328 
1329  v=owl_global_get_current_view(&g);
1330  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
1331  if (!m || owl_view_get_size(v)==0) {
1332    owl_function_error("No message selected\n");
1333    return;
1334  }
1335
1336  owl_fmtext_append_bold(&fm, "General Information:\n");
1337  owl_fmtext_append_normal(&fm, "  Msg Id    : ");
1338  sprintf(buff, "%i", owl_message_get_id(m));
1339  owl_fmtext_append_normal(&fm, buff);
1340  owl_fmtext_append_normal(&fm, "\n");
1341
1342  owl_fmtext_append_normal(&fm, "  Type      : ");
1343  owl_fmtext_append_bold(&fm, owl_message_get_type(m));
1344  owl_fmtext_append_normal(&fm, "\n");
1345
1346  if (owl_message_is_direction_in(m)) {
1347    owl_fmtext_append_normal(&fm, "  Direction : in\n");
1348  } else if (owl_message_is_direction_out(m)) {
1349    owl_fmtext_append_normal(&fm, "  Direction : out\n");
1350  } else if (owl_message_is_direction_none(m)) {
1351    owl_fmtext_append_normal(&fm, "  Direction : none\n");
1352  } else {
1353    owl_fmtext_append_normal(&fm, "  Direction : unknown\n");
1354  }
1355
1356  owl_fmtext_append_normal(&fm, "  Time      : ");
1357  owl_fmtext_append_normal(&fm, owl_message_get_timestr(m));
1358  owl_fmtext_append_normal(&fm, "\n");
1359
1360  if (!owl_message_is_type_admin(m)) {
1361    owl_fmtext_append_normal(&fm, "  Sender    : ");
1362    owl_fmtext_append_normal(&fm, owl_message_get_sender(m));
1363    owl_fmtext_append_normal(&fm, "\n");
1364   
1365    owl_fmtext_append_normal(&fm, "  Recipient : ");
1366    owl_fmtext_append_normal(&fm, owl_message_get_recipient(m));
1367    owl_fmtext_append_normal(&fm, "\n");
1368  }
1369   
1370  if (owl_message_is_type_zephyr(m)) {
1371    owl_fmtext_append_bold(&fm, "\nZephyr Specific Information:\n");
1372   
1373    owl_fmtext_append_normal(&fm, "  Class     : ");
1374    owl_fmtext_append_normal(&fm, owl_message_get_class(m));
1375    owl_fmtext_append_normal(&fm, "\n");
1376    owl_fmtext_append_normal(&fm, "  Instance  : ");
1377    owl_fmtext_append_normal(&fm, owl_message_get_instance(m));
1378    owl_fmtext_append_normal(&fm, "\n");
1379    owl_fmtext_append_normal(&fm, "  Opcode    : ");
1380    owl_fmtext_append_normal(&fm, owl_message_get_opcode(m));
1381    owl_fmtext_append_normal(&fm, "\n");
1382   
1383    owl_fmtext_append_normal(&fm, "  Time      : ");
1384    owl_fmtext_append_normal(&fm, owl_message_get_timestr(m));
1385    owl_fmtext_append_normal(&fm, "\n");
1386#ifdef HAVE_LIBZEPHYR
1387    if (owl_message_is_direction_in(m)) {
1388      char *ptr, tmpbuff[1024];
1389      int i, j, fields, len;
1390
1391      n=owl_message_get_notice(m);
1392
1393      if (!owl_message_is_pseudo(m)) {
1394        owl_fmtext_append_normal(&fm, "  Kind      : ");
1395        if (n->z_kind==UNSAFE) {
1396          owl_fmtext_append_normal(&fm, "UNSAFE\n");
1397        } else if (n->z_kind==UNACKED) {
1398          owl_fmtext_append_normal(&fm, "UNACKED\n");
1399        } else if (n->z_kind==ACKED) {
1400          owl_fmtext_append_normal(&fm, "ACKED\n");
1401        } else if (n->z_kind==HMACK) {
1402          owl_fmtext_append_normal(&fm, "HMACK\n");
1403        } else if (n->z_kind==HMCTL) {
1404          owl_fmtext_append_normal(&fm, "HMCTL\n");
1405        } else if (n->z_kind==SERVACK) {
1406          owl_fmtext_append_normal(&fm, "SERVACK\n");
1407        } else if (n->z_kind==SERVNAK) {
1408          owl_fmtext_append_normal(&fm, "SERVNACK\n");
1409        } else if (n->z_kind==CLIENTACK) {
1410          owl_fmtext_append_normal(&fm, "CLIENTACK\n");
1411        } else if (n->z_kind==STAT) {
1412          owl_fmtext_append_normal(&fm, "STAT\n");
1413        } else {
1414          owl_fmtext_append_normal(&fm, "ILLEGAL VALUE\n");
1415        }
1416      }
1417      owl_fmtext_append_normal(&fm, "  Host      : ");
1418      owl_fmtext_append_normal(&fm, owl_message_get_hostname(m));
1419
1420      if (!owl_message_is_pseudo(m)) {
1421        owl_fmtext_append_normal(&fm, "\n");
1422        sprintf(buff, "  Port      : %i\n", ntohs(n->z_port));
1423        owl_fmtext_append_normal(&fm, buff);
1424
1425        owl_fmtext_append_normal(&fm,    "  Auth      : ");
1426        owl_fmtext_append_normal(&fm, owl_zephyr_get_authstr(n));
1427        owl_fmtext_append_normal(&fm, "\n");
1428       
1429        /* fix this */
1430        sprintf(buff, "  Checkd Ath: %i\n", n->z_checked_auth);
1431        sprintf(buff, "%s  Multi notc: %s\n", buff, n->z_multinotice);
1432        sprintf(buff, "%s  Num other : %i\n", buff, n->z_num_other_fields);
1433        sprintf(buff, "%s  Msg Len   : %i\n", buff, n->z_message_len);
1434        owl_fmtext_append_normal(&fm, buff);
1435       
1436        sprintf(buff, "  Fields    : %i\n", owl_zephyr_get_num_fields(n));
1437        owl_fmtext_append_normal(&fm, buff);
1438       
1439        fields=owl_zephyr_get_num_fields(n);
1440        for (i=0; i<fields; i++) {
1441          sprintf(buff, "  Field %i   : ", i+1);
1442         
1443          ptr=owl_zephyr_get_field_as_utf8(n, i+1);
1444          len=strlen(ptr);
1445          if (len<30) {
1446            strncpy(tmpbuff, ptr, len);
1447            tmpbuff[len]='\0';
1448          } else {
1449            strncpy(tmpbuff, ptr, 30);
1450            tmpbuff[30]='\0';
1451            strcat(tmpbuff, "...");
1452          }
1453          owl_free(ptr);
1454         
1455          for (j=0; j<strlen(tmpbuff); j++) {
1456            if (tmpbuff[j]=='\n') tmpbuff[j]='~';
1457            if (tmpbuff[j]=='\r') tmpbuff[j]='!';
1458          }
1459         
1460          strcat(buff, tmpbuff);
1461          strcat(buff, "\n");
1462          owl_fmtext_append_normal(&fm, buff);
1463        }
1464        owl_fmtext_append_normal(&fm, "  Default Fm:");
1465        owl_fmtext_append_normal(&fm, n->z_default_format);
1466      }
1467     
1468    }
1469#endif   
1470  }
1471
1472  owl_fmtext_append_bold(&fm, "\nOwl Message Attributes:\n");
1473  owl_message_attributes_tofmtext(m, &attrfm);
1474  owl_fmtext_append_fmtext(&fm, &attrfm);
1475 
1476  owl_function_popless_fmtext(&fm);
1477  owl_fmtext_free(&fm);
1478  owl_fmtext_free(&attrfm);
1479}
1480
1481/* print the current message in a popup window.
1482 * Use the 'default' style regardless of whatever
1483 * style the user may be using
1484 */
1485void owl_function_curmsg_to_popwin()
1486{
1487  owl_popwin *pw;
1488  owl_view *v;
1489  owl_message *m;
1490  owl_style *s;
1491  owl_fmtext fm;
1492
1493  v=owl_global_get_current_view(&g);
1494  s=owl_global_get_style_by_name(&g, "default");
1495  pw=owl_global_get_popwin(&g);
1496
1497  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
1498
1499  if (!m || owl_view_get_size(v)==0) {
1500    owl_function_error("No current message");
1501    return;
1502  }
1503
1504  owl_fmtext_init_null(&fm);
1505  owl_style_get_formattext(s, &fm, m);
1506
1507  owl_function_popless_fmtext(&fm);
1508  owl_fmtext_free(&fm);
1509}
1510
1511void owl_function_page_curmsg(int step)
1512{
1513  /* scroll down or up within the current message IF the message is truncated */
1514
1515  int offset, curmsg, lines;
1516  owl_view *v;
1517  owl_message *m;
1518
1519  offset=owl_global_get_curmsg_vert_offset(&g);
1520  v=owl_global_get_current_view(&g);
1521  curmsg=owl_global_get_curmsg(&g);
1522  m=owl_view_get_element(v, curmsg);
1523  if (!m || owl_view_get_size(v)==0) return;
1524  lines=owl_message_get_numlines(m);
1525
1526  if (offset==0) {
1527    /* Bail if the curmsg isn't the last one displayed */
1528    if (curmsg != owl_mainwin_get_last_msg(owl_global_get_mainwin(&g))) {
1529      owl_function_makemsg("The entire message is already displayed");
1530      return;
1531    }
1532   
1533    /* Bail if we're not truncated */
1534    if (!owl_mainwin_is_curmsg_truncated(owl_global_get_mainwin(&g))) {
1535      owl_function_makemsg("The entire message is already displayed");
1536      return;
1537    }
1538  }
1539 
1540 
1541  /* don't scroll past the last line */
1542  if (step>0) {
1543    if (offset+step > lines-1) {
1544      owl_global_set_curmsg_vert_offset(&g, lines-1);
1545    } else {
1546      owl_global_set_curmsg_vert_offset(&g, offset+step);
1547    }
1548  }
1549
1550  /* would we be before the beginning of the message? */
1551  if (step<0) {
1552    if (offset+step<0) {
1553      owl_global_set_curmsg_vert_offset(&g, 0);
1554    } else {
1555      owl_global_set_curmsg_vert_offset(&g, offset+step);
1556    }
1557  }
1558 
1559  /* redisplay */
1560  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1561  owl_global_set_needrefresh(&g);
1562}
1563
1564void owl_function_resize_typwin(int newsize)
1565{
1566  owl_global_set_typwin_lines(&g, newsize);
1567  owl_function_resize();
1568}
1569
1570void owl_function_typwin_grow()
1571{
1572  int i;
1573
1574  i=owl_global_get_typwin_lines(&g);
1575  owl_function_resize_typwin(i+1);
1576}
1577
1578void owl_function_typwin_shrink()
1579{
1580  int i;
1581
1582  i=owl_global_get_typwin_lines(&g);
1583  if (i>2) {
1584    owl_function_resize_typwin(i-1);
1585  }
1586}
1587
1588void owl_function_mainwin_pagedown()
1589{
1590  int i;
1591
1592  i=owl_mainwin_get_last_msg(owl_global_get_mainwin(&g));
1593  if (i<0) return;
1594  if (owl_mainwin_is_last_msg_truncated(owl_global_get_mainwin(&g))
1595      && (owl_global_get_curmsg(&g) < i)
1596      && (i>0)) {
1597    i--;
1598  }
1599  owl_global_set_curmsg(&g, i);
1600  owl_function_nextmsg();
1601}
1602
1603void owl_function_mainwin_pageup()
1604{
1605  owl_global_set_curmsg(&g, owl_global_get_topmsg(&g));
1606  owl_function_prevmsg();
1607}
1608
1609void owl_function_getsubs()
1610{
1611  char *buff;
1612
1613  buff=owl_zephyr_getsubs();
1614
1615  if (buff) {
1616    owl_function_popless_text(buff);
1617  } else {
1618    owl_function_popless_text("Error getting subscriptions");
1619  }
1620           
1621  owl_free(buff);
1622}
1623
1624#define PABUFLEN 5000
1625void owl_function_printallvars()
1626{
1627  char buff[PABUFLEN], *pos, *name;
1628  owl_list varnames;
1629  int i, numvarnames, rem;
1630
1631  pos = buff;
1632  pos += sprintf(pos, "%-20s = %s\n", "VARIABLE", "VALUE");
1633  pos += sprintf(pos, "%-20s   %s\n",  "--------", "-----");
1634  owl_variable_dict_get_names(owl_global_get_vardict(&g), &varnames);
1635  rem = (buff+PABUFLEN)-pos-1;
1636  numvarnames = owl_list_get_size(&varnames);
1637  for (i=0; i<numvarnames; i++) {
1638    name = owl_list_get_element(&varnames, i);
1639    if (name && name[0]!='_') {
1640      rem = (buff+PABUFLEN)-pos-1;   
1641      pos += snprintf(pos, rem, "\n%-20s = ", name);
1642      rem = (buff+PABUFLEN)-pos-1;   
1643      owl_variable_get_tostring(owl_global_get_vardict(&g), name, pos, rem);
1644      pos = buff+strlen(buff);
1645    }
1646  }
1647  rem = (buff+PABUFLEN)-pos-1;   
1648  snprintf(pos, rem, "\n");
1649  owl_variable_dict_namelist_free(&varnames);
1650 
1651  owl_function_popless_text(buff);
1652}
1653
1654void owl_function_show_variables()
1655{
1656  owl_list varnames;
1657  owl_fmtext fm; 
1658  int i, numvarnames;
1659  char *varname;
1660
1661  owl_fmtext_init_null(&fm);
1662  owl_fmtext_append_bold(&fm, 
1663      "Variables: (use 'show variable <name>' for details)\n");
1664  owl_variable_dict_get_names(owl_global_get_vardict(&g), &varnames);
1665  numvarnames = owl_list_get_size(&varnames);
1666  for (i=0; i<numvarnames; i++) {
1667    varname = owl_list_get_element(&varnames, i);
1668    if (varname && varname[0]!='_') {
1669      owl_variable_describe(owl_global_get_vardict(&g), varname, &fm);
1670    }
1671  }
1672  owl_variable_dict_namelist_free(&varnames);
1673  owl_function_popless_fmtext(&fm);
1674  owl_fmtext_free(&fm);
1675}
1676
1677void owl_function_show_variable(char *name)
1678{
1679  owl_fmtext fm; 
1680
1681  owl_fmtext_init_null(&fm);
1682  owl_variable_get_help(owl_global_get_vardict(&g), name, &fm);
1683  owl_function_popless_fmtext(&fm);
1684  owl_fmtext_free(&fm); 
1685}
1686
1687/* note: this applies to global message list, not to view.
1688 * If flag is 1, deletes.  If flag is 0, undeletes. */
1689void owl_function_delete_by_id(int id, int flag)
1690{
1691  owl_messagelist *ml;
1692  owl_message *m;
1693  ml = owl_global_get_msglist(&g);
1694  m = owl_messagelist_get_by_id(ml, id);
1695  if (m) {
1696    if (flag == 1) {
1697      owl_message_mark_delete(m);
1698    } else if (flag == 0) {
1699      owl_message_unmark_delete(m);
1700    }
1701    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1702    owl_global_set_needrefresh(&g);
1703  } else {
1704    owl_function_error("No message with id %d: unable to mark for (un)delete",id);
1705  }
1706}
1707
1708void owl_function_delete_automsgs()
1709{
1710  /* mark for deletion all messages in the current view that match the
1711   * 'trash' filter */
1712
1713  int i, j, count;
1714  owl_message *m;
1715  owl_view *v;
1716  owl_filter *f;
1717
1718  /* get the trash filter */
1719  f=owl_global_get_filter(&g, "trash");
1720  if (!f) {
1721    owl_function_error("No trash filter defined");
1722    return;
1723  }
1724
1725  v=owl_global_get_current_view(&g);
1726
1727  count=0;
1728  j=owl_view_get_size(v);
1729  for (i=0; i<j; i++) {
1730    m=owl_view_get_element(v, i);
1731    if (owl_filter_message_match(f, m)) {
1732      count++;
1733      owl_message_mark_delete(m);
1734    }
1735  }
1736  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1737  owl_function_makemsg("%i messages marked for deletion", count);
1738  owl_global_set_needrefresh(&g);
1739}
1740
1741void owl_function_status()
1742{
1743  char buff[5000];
1744  time_t start;
1745  int up, days, hours, minutes;
1746  owl_fmtext fm;
1747
1748  owl_fmtext_init_null(&fm);
1749
1750  start=owl_global_get_starttime(&g);
1751
1752  owl_fmtext_append_normal(&fm, "General Information:\n");
1753
1754  owl_fmtext_append_normal(&fm, "  Version: ");
1755  owl_fmtext_append_normal(&fm, OWL_VERSION_STRING);
1756  owl_fmtext_append_normal(&fm, "\n");
1757
1758  owl_fmtext_append_normal(&fm, "  Startup Arguments: ");
1759  owl_fmtext_append_normal(&fm, owl_global_get_startupargs(&g));
1760  owl_fmtext_append_normal(&fm, "\n");
1761
1762  owl_fmtext_append_normal(&fm, "  Current Directory: ");
1763  (void) getcwd(buff, MAXPATHLEN);
1764  owl_fmtext_append_normal(&fm, buff);
1765  owl_fmtext_append_normal(&fm, "\n");
1766
1767  sprintf(buff, "  Startup Time: %s", ctime(&start));
1768  owl_fmtext_append_normal(&fm, buff);
1769
1770  up=owl_global_get_runtime(&g);
1771  days=up/86400;
1772  up-=days*86400;
1773  hours=up/3600;
1774  up-=hours*3600;
1775  minutes=up/60;
1776  up-=minutes*60;
1777  sprintf(buff, "  Run Time: %i days %2.2i:%2.2i:%2.2i\n", days, hours, minutes, up);
1778  owl_fmtext_append_normal(&fm, buff);
1779
1780  owl_fmtext_append_normal(&fm, "\nProtocol Options:\n");
1781  owl_fmtext_append_normal(&fm, "  Zephyr included    : ");
1782  if (owl_global_is_havezephyr(&g)) {
1783    owl_fmtext_append_normal(&fm, "yes\n");
1784  } else {
1785    owl_fmtext_append_normal(&fm, "no\n");
1786  }
1787  owl_fmtext_append_normal(&fm, "  AIM included       : no\n");
1788  owl_fmtext_append_normal(&fm, "  Loopback included  : yes\n");
1789
1790
1791  owl_fmtext_append_normal(&fm, "\nBuild Options:\n");
1792  owl_fmtext_append_normal(&fm, "  Stderr redirection : ");
1793#if OWL_STDERR_REDIR
1794  owl_fmtext_append_normal(&fm, "yes\n");
1795#else
1796  owl_fmtext_append_normal(&fm, "no\n");
1797#endif
1798 
1799
1800  owl_function_popless_fmtext(&fm);
1801  owl_fmtext_free(&fm);
1802}
1803
1804void owl_function_show_term()
1805{
1806  owl_fmtext fm;
1807  char buff[LINE];
1808
1809  owl_fmtext_init_null(&fm);
1810  sprintf(buff, "Terminal Lines: %i\nTerminal Columns: %i\n",
1811          owl_global_get_lines(&g),
1812          owl_global_get_cols(&g));
1813  owl_fmtext_append_normal(&fm, buff);
1814
1815  if (owl_global_get_hascolors(&g)) {
1816    owl_fmtext_append_normal(&fm, "Color: Yes\n");
1817    sprintf(buff, "Number of color pairs: %i\n", owl_global_get_colorpairs(&g));
1818    owl_fmtext_append_normal(&fm, buff);
1819    sprintf(buff, "Can change colors: %s\n", can_change_color() ? "yes" : "no");
1820    owl_fmtext_append_normal(&fm, buff);
1821  } else {
1822    owl_fmtext_append_normal(&fm, "Color: No\n");
1823  }
1824
1825  owl_function_popless_fmtext(&fm);
1826  owl_fmtext_free(&fm);
1827}
1828
1829/* if type = 0 then normal reply.
1830 * if type = 1 then it's a reply to sender
1831 * if enter = 0 then allow the command to be edited
1832 * if enter = 1 then don't wait for editing
1833 */
1834void owl_function_reply(int type, int enter)
1835{
1836  char *buff=NULL, *oldbuff;
1837  owl_message *m;
1838  owl_filter *f;
1839 
1840  if (owl_view_get_size(owl_global_get_current_view(&g))==0) {
1841    owl_function_error("No message selected");
1842  } else {
1843    char *class, *inst, *to, *cc=NULL;
1844   
1845    m=owl_view_get_element(owl_global_get_current_view(&g), owl_global_get_curmsg(&g));
1846    if (!m) {
1847      owl_function_error("No message selected");
1848      return;
1849    }
1850
1851    /* first check if we catch the reply-lockout filter */
1852    f=owl_global_get_filter(&g, "reply-lockout");
1853    if (f) {
1854      if (owl_filter_message_match(f, m)) {
1855        owl_function_error("Sorry, replies to this message have been disabled by the reply-lockout filter");
1856        return;
1857      }
1858    }
1859
1860    /* loopback */
1861    if (owl_message_is_type_loopback(m)) {
1862      owl_function_loopwrite_setup();
1863      return;
1864    }
1865
1866    /* zephyr */
1867    if (owl_message_is_type_zephyr(m)) {
1868      /* if it's a zephyr we sent, send it out the same way again */
1869      if (owl_message_is_direction_out(m)) {
1870          buff = owl_strdup(owl_message_get_zwriteline(m));
1871      } else {
1872
1873        /* Special case a personal reply to a webzephyr user on a class */
1874        if ((type==1) && !strcasecmp(owl_message_get_opcode(m), OWL_WEBZEPHYR_OPCODE)) {
1875          class=OWL_WEBZEPHYR_CLASS;
1876          inst=owl_message_get_sender(m);
1877          to=OWL_WEBZEPHYR_PRINCIPAL;
1878        } else if (!strcasecmp(owl_message_get_class(m), OWL_WEBZEPHYR_CLASS) && owl_message_is_loginout(m)) {
1879          /* Special case LOGIN/LOGOUT notifications on class "webzephyr" */
1880          class=OWL_WEBZEPHYR_CLASS;
1881          inst=owl_message_get_instance(m);
1882          to=OWL_WEBZEPHYR_PRINCIPAL;
1883        } else if (owl_message_is_loginout(m)) {
1884          /* Normal LOGIN/LOGOUT messages */
1885          class="MESSAGE";
1886          inst="PERSONAL";
1887          to=owl_message_get_sender(m);
1888        } else if (type==1) {
1889          /* Personal reply */
1890          class="MESSAGE";
1891          inst="PERSONAL";
1892          to=owl_message_get_sender(m);
1893        } else {
1894          /* General reply */
1895          class=owl_message_get_class(m);
1896          inst=owl_message_get_instance(m);
1897          to=owl_message_get_recipient(m);
1898          cc=owl_message_get_cc_without_recipient(m);
1899          if (!strcmp(to, "") || !strcmp(to, "*")) {
1900            to="";
1901          } else if (to[0]=='@') {
1902            /* leave it, to get the realm */
1903          } else {
1904            to=owl_message_get_sender(m);
1905          }
1906        }
1907
1908        /* create the command line */
1909        if (!strcasecmp(owl_message_get_opcode(m), "CRYPT")) {
1910          buff=owl_strdup("zcrypt");
1911        } else {
1912          buff = owl_strdup("zwrite");
1913        }
1914        if (strcasecmp(class, "message")) {
1915          buff = owl_sprintf("%s -c %s%s%s", oldbuff=buff, owl_getquoting(class), class, owl_getquoting(class));
1916          owl_free(oldbuff);
1917        }
1918        if (strcasecmp(inst, "personal")) {
1919          buff = owl_sprintf("%s -i %s%s%s", oldbuff=buff, owl_getquoting(inst), inst, owl_getquoting(inst));
1920          owl_free(oldbuff);
1921        }
1922        if (*to != '\0') {
1923          char *tmp, *oldtmp, *tmp2;
1924          tmp=short_zuser(to);
1925          if (cc) {
1926            tmp = owl_util_uniq(oldtmp=tmp, cc, "-");
1927            owl_free(oldtmp);
1928            buff = owl_sprintf("%s -C %s", oldbuff=buff, tmp);
1929            owl_free(oldbuff);
1930          } else {
1931            if (owl_global_is_smartstrip(&g)) {
1932              tmp2=tmp;
1933              tmp=owl_zephyr_smartstripped_user(tmp2);
1934              owl_free(tmp2);
1935            }
1936            buff = owl_sprintf("%s %s", oldbuff=buff, tmp);
1937            owl_free(oldbuff);
1938          }
1939          owl_free(tmp);
1940        }
1941        if (cc) owl_free(cc);
1942      }
1943    } else {
1944      char *cmd;
1945      if((type==0 && (cmd=owl_message_get_attribute_value(m, "replycmd")))
1946         || (type==1 && (cmd=owl_message_get_attribute_value(m, "replysendercmd")))) {
1947        buff = owl_strdup(cmd);
1948      }
1949    }
1950
1951    if(!buff) {
1952        owl_function_error("I don't know how to reply to that message.");
1953        return;
1954    }
1955   
1956    if (enter) {
1957      owl_history *hist = owl_global_get_cmd_history(&g);
1958      owl_history_store(hist, buff);
1959      owl_history_reset(hist);
1960      owl_function_command_norv(buff);
1961    } else {
1962      owl_function_start_command(buff);
1963    }
1964    owl_free(buff);
1965  }
1966}
1967
1968void owl_function_zlocate(int argc, char **argv, int auth)
1969{
1970  owl_fmtext fm;
1971  char *ptr, buff[LINE];
1972  int i;
1973
1974  owl_fmtext_init_null(&fm);
1975
1976  for (i=0; i<argc; i++) {
1977    ptr=long_zuser(argv[i]);
1978    owl_zephyr_zlocate(ptr, buff, auth);
1979    owl_fmtext_append_normal(&fm, buff);
1980    owl_free(ptr);
1981  }
1982
1983  owl_function_popless_fmtext(&fm);
1984  owl_fmtext_free(&fm);
1985}
1986
1987void owl_function_start_command(char *line)
1988{
1989  owl_editwin *tw;
1990
1991  tw=owl_global_get_typwin(&g);
1992  owl_global_set_typwin_active(&g);
1993  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, 
1994                        owl_global_get_cmd_history(&g));
1995
1996  owl_editwin_set_locktext(tw, "command: ");
1997  owl_global_set_needrefresh(&g);
1998
1999  owl_editwin_insert_string(tw, line);
2000  owl_editwin_redisplay(tw, 0);
2001
2002  owl_context_set_editline(owl_global_get_context(&g), tw);
2003  owl_function_activate_keymap("editline");
2004}
2005
2006void owl_function_start_question(char *line)
2007{
2008  owl_editwin *tw;
2009
2010  tw=owl_global_get_typwin(&g);
2011  owl_global_set_typwin_active(&g);
2012  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, owl_global_get_cmd_history(&g));
2013
2014  owl_editwin_set_locktext(tw, line);
2015  owl_global_set_needrefresh(&g);
2016
2017  owl_editwin_redisplay(tw, 0);
2018
2019  owl_context_set_editresponse(owl_global_get_context(&g), tw);
2020  owl_function_activate_keymap("editresponse");
2021}
2022
2023void owl_function_start_password(char *line)
2024{
2025  owl_editwin *tw;
2026
2027  tw=owl_global_get_typwin(&g);
2028  owl_global_set_typwin_active(&g);
2029  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, owl_global_get_cmd_history(&g));
2030  owl_editwin_set_echochar(tw, '*');
2031
2032  owl_editwin_set_locktext(tw, line);
2033  owl_global_set_needrefresh(&g);
2034
2035  owl_editwin_redisplay(tw, 0);
2036
2037  owl_context_set_editresponse(owl_global_get_context(&g), tw);
2038  owl_function_activate_keymap("editresponse");
2039}
2040
2041char *owl_function_exec(int argc, char **argv, char *buff, int type)
2042{
2043  /* if type == 1 display in a popup
2044   * if type == 2 display an admin messages
2045   * if type == 0 return output
2046   * else display in a popup
2047   */
2048  char *newbuff, *redirect = " 2>&1 < /dev/null";
2049  char *out, buff2[1024];
2050  int size;
2051  FILE *p;
2052
2053#if OWL_STDERR_REDIR
2054  redirect = " < /dev/null";
2055#endif
2056
2057  if (argc<2) {
2058    owl_function_error("Wrong number of arguments to the exec command");
2059    return NULL;
2060  }
2061
2062  buff = skiptokens(buff, 1);
2063  newbuff = owl_malloc(strlen(buff)+strlen(redirect)+1);
2064  strcpy(newbuff, buff);
2065  strcat(newbuff, redirect);
2066
2067  if (type == 1) {
2068    owl_popexec_new(newbuff);
2069  } else {
2070    p=popen(newbuff, "r");
2071    out=owl_malloc(1024);
2072    size=1024;
2073    strcpy(out, "");
2074    while (fgets(buff2, 1024, p)!=NULL) {
2075      size+=1024;
2076      out=owl_realloc(out, size);
2077      strcat(out, buff2);
2078    }
2079    pclose(p);
2080   
2081    if (type==1) {
2082      owl_function_popless_text(out);
2083    } else if (type==0) {
2084      return out;
2085    } else if (type==2) {
2086      owl_function_adminmsg(buff, out);
2087    } else {
2088      owl_function_popless_text(out);
2089    }
2090    owl_free(out);
2091  }
2092  return NULL;
2093}
2094
2095char *owl_function_perl(int argc, char **argv, char *buff, int type)
2096{
2097  /* if type == 1 display in a popup
2098   * if type == 2 display an admin messages
2099   * if type == 0 return output
2100   * else display in a popup
2101   */
2102  char *perlout;
2103
2104  if (argc<2) {
2105    owl_function_error("Wrong number of arguments to perl command");
2106    return NULL;
2107  }
2108
2109  /* consume first token (argv[0]) */
2110  buff = skiptokens(buff, 1);
2111
2112  perlout = owl_perlconfig_execute(buff);
2113  if (perlout) { 
2114    if (type==1) {
2115      owl_function_popless_text(perlout);
2116    } else if (type==2) {
2117      owl_function_adminmsg(buff, perlout);
2118    } else if (type==0) {
2119      return perlout;
2120    } else {
2121      owl_function_popless_text(perlout);
2122    }
2123    owl_free(perlout);
2124  }
2125  return NULL;
2126}
2127
2128/* Change the filter associated with the current view.
2129 * This also figures out which message in the new filter
2130 * should have the pointer.
2131 */
2132void owl_function_change_currentview_filter(char *filtname)
2133{
2134  owl_view *v;
2135  owl_filter *f;
2136  int curid=-1, newpos, curmsg;
2137  owl_message *curm=NULL;
2138
2139  v=owl_global_get_current_view(&g);
2140
2141  curmsg=owl_global_get_curmsg(&g);
2142  if (curmsg==-1) {
2143    owl_function_debugmsg("Hit the curmsg==-1 case in change_view");
2144  } else {
2145    curm=owl_view_get_element(v, curmsg);
2146    if (curm) {
2147      curid=owl_message_get_id(curm);
2148      owl_view_save_curmsgid(v, curid);
2149    }
2150  }
2151
2152  f=owl_global_get_filter(&g, filtname);
2153  if (!f) {
2154    owl_function_error("Unknown filter %s", filtname);
2155    return;
2156  }
2157
2158  owl_view_new_filter(v, f);
2159
2160  /* Figure out what to set the current message to.
2161   * - If the view we're leaving has messages in it, go to the closest message
2162   *   to the last message pointed to in that view.
2163   * - If the view we're leaving is empty, try to restore the position
2164   *   from the last time we were in the new view.  */
2165  if (curm) {
2166    newpos = owl_view_get_nearest_to_msgid(v, curid);
2167  } else {
2168    newpos = owl_view_get_nearest_to_saved(v);
2169  }
2170
2171  owl_global_set_curmsg(&g, newpos);
2172  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
2173  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2174  owl_global_set_direction_downwards(&g);
2175}
2176
2177/* Create a new filter, or replace an existing one
2178 * with a new definition.
2179 */
2180void owl_function_create_filter(int argc, char **argv)
2181{
2182  owl_filter *f;
2183  owl_view *v;
2184  int ret, inuse=0;
2185
2186  if (argc < 2) {
2187    owl_function_error("Wrong number of arguments to filter command");
2188    return;
2189  }
2190
2191  owl_function_debugmsg("owl_function_create_filter: starting to create filter named %s", argv[1]);
2192
2193  v=owl_global_get_current_view(&g);
2194
2195  /* don't touch the all filter */
2196  if (!strcmp(argv[1], "all")) {
2197    owl_function_error("You may not change the 'all' filter.");
2198    return;
2199  }
2200
2201  /* deal with the case of trying change the filter color */
2202  if (argc==4 && !strcmp(argv[2], "-c")) {
2203    f=owl_global_get_filter(&g, argv[1]);
2204    if (!f) {
2205      owl_function_error("The filter '%s' does not exist.", argv[1]);
2206      return;
2207    }
2208    if (owl_util_string_to_color(argv[3])==-1) {
2209      owl_function_error("The color '%s' is not available.", argv[3]);
2210      return;
2211    }
2212    owl_filter_set_fgcolor(f, owl_util_string_to_color(argv[3]));
2213    owl_global_set_needrefresh(&g);
2214    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2215    return;
2216  }
2217  if (argc==4 && !strcmp(argv[2], "-b")) {
2218    f=owl_global_get_filter(&g, argv[1]);
2219    if (!f) {
2220      owl_function_error("The filter '%s' does not exist.", argv[1]);
2221      return;
2222    }
2223    if (owl_util_string_to_color(argv[3])==-1) {
2224      owl_function_error("The color '%s' is not available.", argv[3]);
2225      return;
2226    }
2227    owl_filter_set_bgcolor(f, owl_util_string_to_color(argv[3]));
2228    owl_global_set_needrefresh(&g);
2229    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2230    return;
2231  }
2232
2233  /* create the filter and check for errors */
2234  f=owl_malloc(sizeof(owl_filter));
2235  ret=owl_filter_init(f, argv[1], argc-2, argv+2);
2236  if (ret==-1) {
2237    owl_free(f);
2238    owl_function_error("Invalid filter");
2239    return;
2240  }
2241
2242  /* if the named filter is in use by the current view, remember it */
2243  if (!strcmp(owl_view_get_filtname(v), argv[1])) {
2244    inuse=1;
2245  }
2246
2247  /* if the named filter already exists, nuke it */
2248  if (owl_global_get_filter(&g, argv[1])) {
2249    owl_global_remove_filter(&g, argv[1]);
2250  }
2251
2252  /* add the filter */
2253  owl_global_add_filter(&g, f);
2254
2255  /* if it was in use by the current view then update */
2256  if (inuse) {
2257    owl_function_change_currentview_filter(argv[1]);
2258  }
2259  owl_global_set_needrefresh(&g);
2260  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2261}
2262
2263/* If 'filtername' does not start with 'not-' create a filter named
2264 * 'not-<filtername>' defined as "not filter <filtername>".  If the
2265 * filter 'not-<filtername>' already exists, do not overwrite it.  If
2266 * 'filtername' begins with 'not-' and a filter 'filtername' already
2267 * exists, then do nothing.  If the filter 'filtername' does not
2268 * exist, create it and define it as 'not filter <filtername>'
2269 *
2270 * Returns the name of the negated filter, which the caller must free.
2271 */
2272char *owl_function_create_negative_filter(char *filtername)
2273{
2274  char *newname;
2275  owl_filter *tmpfilt;
2276  char *argv[5];
2277
2278  owl_function_debugmsg("owl_function_create_negative_filter");
2279 
2280  if (!strncmp(filtername, "not-", 4)) {
2281    newname=owl_strdup(filtername+4);
2282  } else {
2283    newname=owl_sprintf("not-%s", filtername);
2284  }
2285
2286  tmpfilt=owl_global_get_filter(&g, newname);
2287  if (!tmpfilt) {
2288    argv[0]="filter"; /* anything is fine here */
2289    argv[1]=newname;
2290    argv[2]="not";
2291    argv[3]="filter";
2292    argv[4]=filtername;
2293    owl_function_create_filter(5, argv);
2294  }
2295
2296  owl_function_debugmsg("owl_function_create_negative_filter: returning with %s", newname);
2297  return(newname);
2298}
2299
2300void owl_function_show_filters()
2301{
2302  owl_list *l;
2303  owl_filter *f;
2304  int i, j;
2305  owl_fmtext fm;
2306
2307  owl_fmtext_init_null(&fm);
2308
2309  l=owl_global_get_filterlist(&g);
2310  j=owl_list_get_size(l);
2311
2312  owl_fmtext_append_bold(&fm, "Filters:\n");
2313
2314  for (i=0; i<j; i++) {
2315    f=owl_list_get_element(l, i);
2316    owl_fmtext_append_normal(&fm, "   ");
2317    if (owl_global_get_hascolors(&g)) {
2318      owl_fmtext_append_normal_color(&fm, owl_filter_get_name(f), owl_filter_get_fgcolor(f), owl_filter_get_bgcolor(f));
2319    } else {
2320      owl_fmtext_append_normal(&fm, owl_filter_get_name(f));
2321    }
2322    owl_fmtext_append_normal(&fm, "\n");
2323  }
2324  owl_function_popless_fmtext(&fm);
2325  owl_fmtext_free(&fm);
2326}
2327
2328void owl_function_show_filter(char *name)
2329{
2330  owl_filter *f;
2331  char buff[5000];
2332
2333  f=owl_global_get_filter(&g, name);
2334  if (!f) {
2335    owl_function_error("There is no filter named %s", name);
2336    return;
2337  }
2338  owl_filter_print(f, buff);
2339  owl_function_popless_text(buff);
2340}
2341
2342void owl_function_show_zpunts()
2343{
2344  owl_filter *f;
2345  owl_list *fl;
2346  char buff[5000];
2347  owl_fmtext fm;
2348  int i, j;
2349
2350  owl_fmtext_init_null(&fm);
2351
2352  fl=owl_global_get_puntlist(&g);
2353  j=owl_list_get_size(fl);
2354  owl_fmtext_append_bold(&fm, "Active zpunt filters:\n");
2355
2356  for (i=0; i<j; i++) {
2357    f=owl_list_get_element(fl, i);
2358    snprintf(buff, sizeof(buff), "[% 2d] ", i+1);
2359    owl_fmtext_append_normal(&fm, buff);
2360    owl_filter_print(f, buff);
2361    owl_fmtext_append_normal(&fm, buff);
2362  }
2363  owl_function_popless_fmtext(&fm);
2364  owl_fmtext_free(&fm);
2365}
2366
2367/* Create a filter for a class, instance if one doesn't exist.  If
2368 * instance is NULL then catch all messgaes in the class.  Returns the
2369 * name of the filter, which the caller must free.
2370 */
2371char *owl_function_classinstfilt(char *c, char *i) 
2372{
2373  owl_list *fl;
2374  owl_filter *f;
2375  char *argbuff, *filtname;
2376  char *tmpclass, *tmpinstance = NULL;
2377  char *class, *instance = NULL;
2378  int len;
2379
2380  class = owl_util_baseclass(c);
2381  if(i) {
2382    instance = owl_util_baseclass(i);
2383  }
2384
2385  fl=owl_global_get_filterlist(&g);
2386
2387  /* name for the filter */
2388  len=strlen(class)+30;
2389  if (instance) len+=strlen(instance);
2390  filtname=owl_malloc(len);
2391  if (!instance) {
2392    sprintf(filtname, "class-%s", class);
2393  } else {
2394    sprintf(filtname, "class-%s-instance-%s", class, instance);
2395  }
2396  /* downcase it */
2397  {
2398    char *temp = g_utf8_strdown(filtname, -1);
2399    if (temp) {
2400      owl_free(filtname);
2401      filtname = temp;
2402    }
2403  }
2404  /* turn spaces, single quotes, and double quotes into dots */
2405  owl_text_tr(filtname, ' ', '.');
2406  owl_text_tr(filtname, '\'', '.');
2407  owl_text_tr(filtname, '"', '.');
2408 
2409  /* if it already exists then go with it.  This lets users override */
2410  if (owl_global_get_filter(&g, filtname)) {
2411    return(filtname);
2412  }
2413
2414  /* create the new filter */
2415  tmpclass=owl_text_quote(class, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2416  owl_text_tr(tmpclass, ' ', '.');
2417  owl_text_tr(tmpclass, '\'', '.');
2418  owl_text_tr(tmpclass, '"', '.');
2419  if (instance) {
2420    tmpinstance=owl_text_quote(instance, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2421    owl_text_tr(tmpinstance, ' ', '.');
2422    owl_text_tr(tmpinstance, '\'', '.');
2423    owl_text_tr(tmpinstance, '"', '.');
2424  }
2425  len = strlen(tmpclass);
2426  if(tmpinstance) len += strlen(tmpinstance);
2427  len += 60;
2428  argbuff = owl_malloc(len);
2429  sprintf(argbuff, "class ^(un)*%s(\\.d)*$", tmpclass);
2430  if (tmpinstance) {
2431    sprintf(argbuff, "%s and ( instance ^(un)*%s(\\.d)*$ )", argbuff, tmpinstance);
2432  }
2433  owl_free(tmpclass);
2434  if (tmpinstance) owl_free(tmpinstance);
2435
2436  f=owl_malloc(sizeof(owl_filter));
2437  owl_filter_init_fromstring(f, filtname, argbuff);
2438
2439  /* add it to the global list */
2440  owl_global_add_filter(&g, f);
2441
2442  owl_free(argbuff);
2443  owl_free(class);
2444  if (instance) {
2445    owl_free(instance);
2446  }
2447  return(filtname);
2448}
2449
2450/* Create a filter for personal zephyrs to or from the specified
2451 * zephyr user.  Includes login/logout notifications for the user.
2452 * The name of the filter will be 'user-<user>'.  If a filter already
2453 * exists with this name, no new filter will be created.  This allows
2454 * the configuration to override this function.  Returns the name of
2455 * the filter, which the caller must free.
2456 */
2457char *owl_function_zuserfilt(char *user)
2458{
2459  owl_filter *f;
2460  char *argbuff, *longuser, *shortuser, *filtname;
2461
2462  /* stick the local realm on if it's not there */
2463  longuser=long_zuser(user);
2464  shortuser=short_zuser(user);
2465
2466  /* name for the filter */
2467  filtname=owl_malloc(strlen(shortuser)+20);
2468  sprintf(filtname, "user-%s", shortuser);
2469
2470  /* if it already exists then go with it.  This lets users override */
2471  if (owl_global_get_filter(&g, filtname)) {
2472    return(owl_strdup(filtname));
2473  }
2474
2475  /* create the new-internal filter */
2476  f=owl_malloc(sizeof(owl_filter));
2477
2478  argbuff=owl_malloc(strlen(longuser)+1000);
2479  sprintf(argbuff, "( type ^zephyr$ and filter personal and ");
2480  sprintf(argbuff, "%s ( ( direction ^in$ and sender ^%s$ ) or ( direction ^out$ and recipient ^%s$ ) ) )", argbuff, longuser, longuser);
2481  sprintf(argbuff, "%s or ( ( class ^login$ ) and ( sender ^%s$ ) )", argbuff, longuser);
2482
2483  owl_filter_init_fromstring(f, filtname, argbuff);
2484
2485  /* add it to the global list */
2486  owl_global_add_filter(&g, f);
2487
2488  /* free stuff */
2489  owl_free(argbuff);
2490  owl_free(longuser);
2491  owl_free(shortuser);
2492
2493  return(filtname);
2494}
2495
2496char *owl_function_typefilt(char *type)
2497{
2498  owl_filter *f;
2499  char *argbuff, *filtname;
2500
2501  /* name for the filter */
2502  filtname=owl_sprintf("type-%s", type);
2503
2504  /* if it already exists then go with it.  This lets users override */
2505  if (owl_global_get_filter(&g, filtname)) {
2506    return filtname;
2507  }
2508
2509  /* create the new-internal filter */
2510  f=owl_malloc(sizeof(owl_filter));
2511
2512  argbuff = owl_sprintf("type ^%s$", type);
2513
2514  owl_filter_init_fromstring(f, filtname, argbuff);
2515
2516  /* add it to the global list */
2517  owl_global_add_filter(&g, f);
2518
2519  /* free stuff */
2520  owl_free(argbuff);
2521
2522  return filtname;
2523}
2524
2525/* If flag is 1, marks for deletion.  If flag is 0,
2526 * unmarks for deletion. */
2527void owl_function_delete_curview_msgs(int flag)
2528{
2529  owl_view *v;
2530  int i, j;
2531
2532  v=owl_global_get_current_view(&g);
2533  j=owl_view_get_size(v);
2534  for (i=0; i<j; i++) {
2535    if (flag == 1) {
2536      owl_message_mark_delete(owl_view_get_element(v, i));
2537    } else if (flag == 0) {
2538      owl_message_unmark_delete(owl_view_get_element(v, i));
2539    }
2540  }
2541
2542  owl_function_makemsg("%i messages marked for %sdeletion", j, flag?"":"un");
2543
2544  owl_mainwin_redisplay(owl_global_get_mainwin(&g)); 
2545}
2546
2547/* Create a filter based on the current message.  Returns the name of
2548 * a filter or null.  The caller must free this name.
2549 *
2550 * if the curmsg is a personal zephyr return a filter name
2551 *    to the zephyr converstaion with that user.
2552 * If the curmsg is a zephyr class message, instance foo, recip *,
2553 *    return a filter name to the class, inst.
2554 * If the curmsg is a zephyr class message and type==0 then
2555 *    return a filter name for just the class.
2556 * If the curmsg is a zephyr class message and type==1 then
2557 *    return a filter name for the class and instance.
2558 * If the curmsg is a personal AIM message returna  filter
2559 *    name to the AIM conversation with that user
2560 */
2561char *owl_function_smartfilter(int type)
2562{
2563  owl_view *v;
2564  owl_message *m;
2565  char *zperson, *filtname=NULL;
2566  char *argv[1];
2567 
2568  v=owl_global_get_current_view(&g);
2569  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2570
2571  if (!m || owl_view_get_size(v)==0) {
2572    owl_function_error("No message selected\n");
2573    return(NULL);
2574  }
2575
2576  /* very simple handling of admin messages for now */
2577  if (owl_message_is_type_admin(m)) {
2578    return(owl_function_typefilt("admin"));
2579  }
2580
2581  /* very simple handling of loopback messages for now */
2582  if (owl_message_is_type_loopback(m)) {
2583    return(owl_function_typefilt("loopback"));
2584  }
2585
2586  /* narrow personal and login messages to the sender or recip as appropriate */
2587  if (owl_message_is_type_zephyr(m)) {
2588    if (owl_message_is_personal(m) || owl_message_is_loginout(m)) {
2589      if (owl_message_is_direction_in(m)) {
2590        zperson=short_zuser(owl_message_get_sender(m));
2591      } else {
2592        zperson=short_zuser(owl_message_get_recipient(m));
2593      }
2594      filtname=owl_function_zuserfilt(zperson);
2595      owl_free(zperson);
2596      return(filtname);
2597    }
2598
2599    /* narrow class MESSAGE, instance foo, recip * messages to class, inst */
2600    if (!strcasecmp(owl_message_get_class(m), "message")) {
2601      filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2602      return(filtname);
2603    }
2604
2605    /* otherwise narrow to the class */
2606    if (type==0) {
2607      filtname=owl_function_classinstfilt(owl_message_get_class(m), NULL);
2608    } else if (type==1) {
2609      filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2610    }
2611    return(filtname);
2612  }
2613
2614  /* pass it off to perl */
2615  if(type) {
2616    argv[0] = "-i";
2617  };
2618  return owl_perlconfig_message_call_method(m, "smartfilter", type ? 1 : 0, argv);
2619}
2620
2621void owl_function_smartzpunt(int type)
2622{
2623  /* Starts a zpunt command based on the current class,instance pair.
2624   * If type=0, uses just class.  If type=1, uses instance as well. */
2625  owl_view *v;
2626  owl_message *m;
2627  char *cmd, *cmdprefix, *mclass, *minst;
2628 
2629  v=owl_global_get_current_view(&g);
2630  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2631
2632  if (!m || owl_view_get_size(v)==0) {
2633    owl_function_error("No message selected\n");
2634    return;
2635  }
2636
2637  /* for now we skip admin messages. */
2638  if (owl_message_is_type_admin(m)
2639      || owl_message_is_loginout(m)
2640      || !owl_message_is_type_zephyr(m)) {
2641    owl_function_error("smartzpunt doesn't support this message type.");
2642    return;
2643  }
2644
2645  mclass = owl_message_get_class(m);
2646  minst = owl_message_get_instance(m);
2647  if (!mclass || !*mclass || *mclass==' '
2648      || (!strcasecmp(mclass, "message") && !strcasecmp(minst, "personal"))
2649      || (type && (!minst || !*minst|| *minst==' '))) {
2650    owl_function_error("smartzpunt can't safely do this for <%s,%s>",
2651                         mclass, minst);
2652  } else {
2653    cmdprefix = "start-command zpunt ";
2654    cmd = owl_malloc(strlen(cmdprefix)+strlen(mclass)+strlen(minst)+10);
2655    strcpy(cmd, cmdprefix);
2656    strcat(cmd, owl_getquoting(mclass));
2657    strcat(cmd, mclass);
2658    strcat(cmd, owl_getquoting(mclass));
2659    if (type) {
2660      strcat(cmd, " ");
2661      strcat(cmd, owl_getquoting(minst));
2662      strcat(cmd, minst);
2663      strcat(cmd, owl_getquoting(minst));
2664    } else {
2665      strcat(cmd, " *");
2666    }
2667    owl_function_command(cmd);
2668    owl_free(cmd);
2669  }
2670}
2671
2672/* Set the color of the current view's filter to
2673 * be 'color'
2674 */
2675void owl_function_color_current_filter(char *fgcolor, char *bgcolor)
2676{
2677  char *name;
2678
2679  name=owl_view_get_filtname(owl_global_get_current_view(&g));
2680  owl_function_color_filter(name, fgcolor, bgcolor);
2681}
2682
2683/* Set the color of the filter 'filter' to be 'color'.  If the color
2684 * name does not exist, return -1, if the filter does not exist or is
2685 * the "all" filter, return -2.  Return 0 on success
2686 */
2687int owl_function_color_filter(char *filtname, char *fgcolor, char *bgcolor)
2688{
2689  owl_filter *f;
2690
2691  f=owl_global_get_filter(&g, filtname);
2692  if (!f) {
2693    owl_function_error("Unknown filter");
2694    return(-2);
2695  }
2696
2697  /* don't touch the all filter */
2698  if (!strcmp(filtname, "all")) {
2699    owl_function_error("You may not change the 'all' filter.");
2700    return(-2);
2701  }
2702
2703  if (owl_util_string_to_color(fgcolor)==-1) {
2704    owl_function_error("No color named '%s' avilable.", fgcolor);
2705    return(-1);
2706  }
2707
2708
2709  if (bgcolor != NULL) {
2710    if (owl_util_string_to_color(bgcolor)==-1) {
2711      owl_function_error("No color named '%s' avilable.", bgcolor);
2712      return(-1);
2713    }
2714    owl_filter_set_bgcolor(f, owl_util_string_to_color(bgcolor));
2715  }
2716  owl_filter_set_fgcolor(f, owl_util_string_to_color(fgcolor));
2717 
2718  owl_global_set_needrefresh(&g);
2719  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2720  return(0);
2721}
2722
2723void owl_function_show_colors()
2724{
2725  owl_fmtext fm;
2726  int i; 
2727 
2728  owl_fmtext_init_null(&fm);
2729  owl_fmtext_append_normal(&fm, "default: ");
2730  owl_fmtext_append_normal_color(&fm, "default\n", OWL_COLOR_DEFAULT, OWL_COLOR_DEFAULT);
2731
2732  owl_fmtext_append_normal(&fm,"red:      ");
2733  owl_fmtext_append_normal_color(&fm, "red\n", OWL_COLOR_RED, OWL_COLOR_DEFAULT);
2734
2735  owl_fmtext_append_normal(&fm,"green:    ");
2736  owl_fmtext_append_normal_color(&fm, "green\n", OWL_COLOR_GREEN, OWL_COLOR_DEFAULT);
2737
2738  owl_fmtext_append_normal(&fm,"yellow:   ");
2739  owl_fmtext_append_normal_color(&fm, "yellow\n", OWL_COLOR_YELLOW, OWL_COLOR_DEFAULT);
2740
2741  owl_fmtext_append_normal(&fm,"blue:     ");
2742  owl_fmtext_append_normal_color(&fm, "blue\n", OWL_COLOR_BLUE, OWL_COLOR_DEFAULT);
2743
2744  owl_fmtext_append_normal(&fm,"magenta:  ");
2745  owl_fmtext_append_normal_color(&fm, "magenta\n", OWL_COLOR_MAGENTA, OWL_COLOR_DEFAULT);
2746
2747  owl_fmtext_append_normal(&fm,"cyan:     ");
2748  owl_fmtext_append_normal_color(&fm, "cyan\n", OWL_COLOR_CYAN, OWL_COLOR_DEFAULT);
2749
2750  owl_fmtext_append_normal(&fm,"white:    ");
2751  owl_fmtext_append_normal_color(&fm, "white\n", OWL_COLOR_WHITE, OWL_COLOR_DEFAULT);
2752
2753  for(i = 8; i < COLORS; ++i) {
2754    char* str1 = owl_sprintf("%4i:     ",i);
2755    char* str2 = owl_sprintf("%i\n",i);
2756    owl_fmtext_append_normal(&fm,str1);
2757    owl_fmtext_append_normal_color(&fm, str2, i, OWL_COLOR_DEFAULT);
2758    owl_free(str1);
2759     owl_free(str2);
2760  }
2761 
2762  owl_function_popless_fmtext(&fm);
2763  owl_fmtext_free(&fm);
2764}
2765
2766/* add the given class, inst, recip to the punt list for filtering.
2767 *   if direction==0 then punt
2768 *   if direction==1 then unpunt
2769 */
2770void owl_function_zpunt(char *class, char *inst, char *recip, int direction)
2771{
2772  char *buff;
2773  char *quoted;
2774
2775  buff=owl_malloc(strlen(class)+strlen(inst)+strlen(recip)+100);
2776  strcpy(buff, "class");
2777  if (!strcmp(class, "*")) {
2778    strcat(buff, " .*");
2779  } else {
2780    quoted=owl_text_quote(class, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2781    owl_text_tr(quoted, ' ', '.');
2782    owl_text_tr(quoted, '\'', '.');
2783    owl_text_tr(quoted, '"', '.');
2784    sprintf(buff, "%s ^(un)*%s(\\.d)*$", buff, quoted);
2785    owl_free(quoted);
2786  }
2787  if (!strcmp(inst, "*")) {
2788    strcat(buff, " and instance .*");
2789  } else {
2790    quoted=owl_text_quote(inst, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2791    owl_text_tr(quoted, ' ', '.');
2792    owl_text_tr(quoted, '\'', '.');
2793    owl_text_tr(quoted, '"', '.');
2794    sprintf(buff, "%s and instance ^(un)*%s(\\.d)*$", buff, quoted);
2795    owl_free(quoted);
2796  }
2797  if (strcmp(recip, "*")) {
2798    quoted=owl_text_quote(recip, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2799    owl_text_tr(quoted, ' ', '.');
2800    owl_text_tr(quoted, '\'', '.');
2801    owl_text_tr(quoted, '"', '.');
2802    sprintf(buff, "%s and recipient ^%s$", buff, quoted);
2803    owl_free(quoted);
2804  }
2805
2806  owl_function_punt(buff, direction);
2807  owl_free(buff);
2808}
2809
2810void owl_function_punt(char *filter, int direction)
2811{
2812  owl_filter *f;
2813  owl_list *fl;
2814  int ret, i, j;
2815  fl=owl_global_get_puntlist(&g);
2816
2817  /* first, create the filter */
2818  f=malloc(sizeof(owl_filter));
2819
2820  owl_function_debugmsg("About to filter %s", filter);
2821  ret=owl_filter_init_fromstring(f, "punt-filter", filter);
2822  if (ret) {
2823    owl_function_error("Error creating filter for zpunt");
2824    owl_filter_free(f);
2825    return;
2826  }
2827
2828  /* Check for an identical filter */
2829  j=owl_list_get_size(fl);
2830  for (i=0; i<j; i++) {
2831    if (owl_filter_equiv(f, owl_list_get_element(fl, i))) {
2832      owl_function_debugmsg("found an equivalent punt filter");
2833      /* if we're punting, then just silently bow out on this duplicate */
2834      if (direction==0) {
2835        owl_filter_free(f);
2836        return;
2837      }
2838
2839      /* if we're unpunting, then remove this filter from the puntlist */
2840      if (direction==1) {
2841        owl_filter_free(owl_list_get_element(fl, i));
2842        owl_list_remove_element(fl, i);
2843        owl_filter_free(f);
2844        return;
2845      }
2846    }
2847  }
2848
2849  owl_function_debugmsg("punting");
2850  /* If we're punting, add the filter to the global punt list */
2851  if (direction==0) {
2852    owl_list_append_element(fl, f);
2853  }
2854}
2855
2856void owl_function_activate_keymap(char *keymap)
2857{
2858  if (!owl_keyhandler_activate(owl_global_get_keyhandler(&g), keymap)) {
2859    owl_function_error("Unable to activate keymap '%s'", keymap);
2860  }
2861}
2862
2863void owl_function_show_keymaps()
2864{
2865  owl_list l;
2866  owl_fmtext fm;
2867  owl_keymap *km;
2868  owl_keyhandler *kh;
2869  int i, numkm;
2870  char *kmname;
2871
2872  kh = owl_global_get_keyhandler(&g);
2873  owl_fmtext_init_null(&fm);
2874  owl_fmtext_append_bold(&fm, "Keymaps:   ");
2875  owl_fmtext_append_normal(&fm, "(use 'show keymap <name>' for details)\n");
2876  owl_keyhandler_get_keymap_names(kh, &l);
2877  owl_fmtext_append_list(&fm, &l, "\n", owl_function_keymap_summary);
2878  owl_fmtext_append_normal(&fm, "\n");
2879
2880  numkm = owl_list_get_size(&l);
2881  for (i=0; i<numkm; i++) {
2882    kmname = owl_list_get_element(&l, i);
2883    km = owl_keyhandler_get_keymap(kh, kmname);
2884    owl_fmtext_append_bold(&fm, "\n\n----------------------------------------------------------------------------------------------------\n\n");
2885    owl_keymap_get_details(km, &fm);   
2886  }
2887  owl_fmtext_append_normal(&fm, "\n");
2888 
2889  owl_function_popless_fmtext(&fm);
2890  owl_keyhandler_keymap_namelist_free(&l);
2891  owl_fmtext_free(&fm);
2892}
2893
2894char *owl_function_keymap_summary(void *name)
2895{
2896  owl_keymap *km
2897    = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
2898  if (km) return owl_keymap_summary(km);
2899  else return(NULL);
2900}
2901
2902/* TODO: implement for real */
2903void owl_function_show_keymap(char *name)
2904{
2905  owl_fmtext fm;
2906  owl_keymap *km;
2907
2908  owl_fmtext_init_null(&fm);
2909  km = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
2910  if (km) {
2911    owl_keymap_get_details(km, &fm);
2912  } else {
2913    owl_fmtext_append_normal(&fm, "No such keymap...\n");
2914  } 
2915  owl_function_popless_fmtext(&fm);
2916  owl_fmtext_free(&fm);
2917}
2918
2919void owl_function_help_for_command(char *cmdname)
2920{
2921  owl_fmtext fm;
2922
2923  owl_fmtext_init_null(&fm);
2924  owl_cmd_get_help(owl_global_get_cmddict(&g), cmdname, &fm);
2925  owl_function_popless_fmtext(&fm); 
2926  owl_fmtext_free(&fm);
2927}
2928
2929void owl_function_search_start(char *string, int direction)
2930{
2931  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
2932  owl_global_set_search_active(&g, string);
2933  owl_function_search_helper(0, direction);
2934}
2935
2936void owl_function_search_continue(int direction)
2937{
2938  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
2939  owl_function_search_helper(1, direction);
2940}
2941
2942void owl_function_search_helper(int mode, int direction)
2943{
2944  /* move to a message that contains the string.  If direction is
2945   * OWL_DIRECTION_DOWNWARDS then search fowards, if direction is
2946   * OWL_DIRECTION_UPWARDS then search backwards.
2947   *
2948   * If mode==0 then it will stay on the current message if it
2949   * contains the string.
2950   */
2951
2952  owl_view *v;
2953  int viewsize, i, curmsg, start;
2954  owl_message *m;
2955
2956  v=owl_global_get_current_view(&g);
2957  viewsize=owl_view_get_size(v);
2958  curmsg=owl_global_get_curmsg(&g);
2959 
2960  if (viewsize==0) {
2961    owl_function_error("No messages present");
2962    return;
2963  }
2964
2965  if (mode==0) {
2966    start=curmsg;
2967  } else if (direction==OWL_DIRECTION_DOWNWARDS) {
2968    start=curmsg+1;
2969  } else {
2970    start=curmsg-1;
2971  }
2972
2973  /* bounds check */
2974  if (start>=viewsize || start<0) {
2975    owl_function_error("No further matches found");
2976    return;
2977  }
2978
2979  for (i=start; i<viewsize && i>=0;) {
2980    m=owl_view_get_element(v, i);
2981    if (owl_message_search(m, owl_global_get_search_string(&g))) {
2982      owl_global_set_curmsg(&g, i);
2983      owl_function_calculate_topmsg(direction);
2984      owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2985      if (direction==OWL_DIRECTION_DOWNWARDS) {
2986        owl_global_set_direction_downwards(&g);
2987      } else {
2988        owl_global_set_direction_upwards(&g);
2989      }
2990      return;
2991    }
2992    if (direction==OWL_DIRECTION_DOWNWARDS) {
2993      i++;
2994    } else {
2995      i--;
2996    }
2997  }
2998  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2999  owl_function_error("No matches found");
3000}
3001
3002/* strips formatting from ztext and returns the unformatted text.
3003 * caller is responsible for freeing. */
3004char *owl_function_ztext_stylestrip(char *zt)
3005{
3006  owl_fmtext fm;
3007  char *plaintext;
3008
3009  owl_fmtext_init_null(&fm);
3010  owl_fmtext_append_ztext(&fm, zt);
3011  plaintext = owl_fmtext_print_plain(&fm);
3012  owl_fmtext_free(&fm);
3013  return(plaintext);
3014}
3015
3016/* Popup a buddylisting.  If filename is NULL use the default .anyone */
3017void owl_function_buddylist(int aim, int zephyr, char *filename)
3018{
3019  int i, j, x;
3020  owl_fmtext fm;
3021  owl_list anyone;
3022#ifdef HAVE_LIBZEPHYR
3023  char *tmp, *user, *line;
3024  ZLocations_t location[200];
3025  int numlocs, ret;
3026#endif
3027
3028  owl_fmtext_init_null(&fm);
3029
3030  if (aim && !zephyr)
3031    owl_fmtext_append_normal(&fm, "Warning: AIM support in C has been disabled.\n");
3032
3033#ifdef HAVE_LIBZEPHYR
3034  if (zephyr) {
3035    if(!owl_global_is_havezephyr(&g)) {
3036      owl_function_error("Zephyr currently not available.");
3037    } else {
3038      owl_fmtext_append_bold(&fm, "Zephyr users logged in:\n");
3039      owl_list_create(&anyone);
3040      ret=owl_zephyr_get_anyone_list(&anyone, filename);
3041      if (ret) {
3042        owl_fmtext_append_normal(&fm, "  Error opening file for zephyr buddies.\n");
3043      } else {
3044        j=owl_list_get_size(&anyone);
3045        for (i=0; i<j; i++) {
3046          user=owl_list_get_element(&anyone, i);
3047          ret=ZLocateUser(user, &numlocs, ZAUTH);
3048          if (ret!=ZERR_NONE) {
3049            owl_function_error("Error getting location for %s", user);
3050            continue;
3051          }
3052
3053          numlocs=200;
3054          ret=ZGetLocations(location, &numlocs);
3055          if (ret==0) {
3056            for (x=0; x<numlocs; x++) {
3057              line=owl_malloc(strlen(location[x].host)+strlen(location[x].time)+strlen(location[x].tty)+100);
3058              tmp=short_zuser(user);
3059              sprintf(line, "  %-10.10s %-24.24s %-12.12s  %20.20s\n",
3060                      tmp,
3061                      location[x].host,
3062                      location[x].tty,
3063                      location[x].time);
3064              owl_fmtext_append_normal(&fm, line);
3065              owl_free(tmp);
3066              owl_free(line);
3067            }
3068            if (numlocs>=200) {
3069              owl_fmtext_append_normal(&fm, "  Too many locations found for this user, truncating.\n");
3070            }
3071          }
3072        }
3073      }
3074      owl_list_free_all(&anyone, owl_free);
3075    } 
3076  }
3077#endif
3078
3079  if(aim && zephyr) {
3080      if(owl_perlconfig_is_function("BarnOwl::Hooks::_get_blist")) {
3081          char * perlblist = owl_perlconfig_execute("BarnOwl::Hooks::_get_blist()");
3082          if(perlblist) {
3083              owl_fmtext_append_ztext(&fm, perlblist);
3084              owl_free(perlblist);
3085          }
3086      }
3087  }
3088 
3089  owl_function_popless_fmtext(&fm);
3090  owl_fmtext_free(&fm);
3091}
3092
3093/* Dump messages in the current view to the file 'filename'. */
3094void owl_function_dump(char *filename) 
3095{
3096  int i, j, count;
3097  owl_message *m;
3098  owl_view *v;
3099  FILE *file;
3100  char *plaintext;
3101
3102  v=owl_global_get_current_view(&g);
3103
3104  /* in the future make it ask yes/no */
3105  /*
3106  ret=stat(filename, &sbuf);
3107  if (!ret) {
3108    ret=owl_function_askyesno("File exists, continue? [Y/n]");
3109    if (!ret) return;
3110  }
3111  */
3112
3113  file=fopen(filename, "w");
3114  if (!file) {
3115    owl_function_error("Error opening file");
3116    return;
3117  }
3118
3119  count=0;
3120  j=owl_view_get_size(v);
3121  for (i=0; i<j; i++) {
3122    m=owl_view_get_element(v, i);
3123    plaintext = owl_strip_format_chars(owl_message_get_text(m));
3124    if (plaintext) {
3125      fputs(plaintext, file);
3126      owl_free(plaintext);
3127    }
3128  }
3129  fclose(file);
3130  owl_function_makemsg("Messages dumped to %s", filename);
3131}
3132
3133void owl_function_do_newmsgproc(void)
3134{
3135  if (owl_global_get_newmsgproc(&g) && strcmp(owl_global_get_newmsgproc(&g), "")) {
3136    /* if there's a process out there, we need to check on it */
3137    if (owl_global_get_newmsgproc_pid(&g)) {
3138      owl_function_debugmsg("Checking on newmsgproc pid==%i", owl_global_get_newmsgproc_pid(&g));
3139      owl_function_debugmsg("Waitpid return is %i", waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG));
3140      waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG);
3141      if (waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG)==-1) {
3142        /* it exited */
3143        owl_global_set_newmsgproc_pid(&g, 0);
3144        owl_function_debugmsg("newmsgproc exited");
3145      } else {
3146        owl_function_debugmsg("newmsgproc did not exit");
3147      }
3148    }
3149   
3150    /* if it exited, fork & exec a new one */
3151    if (owl_global_get_newmsgproc_pid(&g)==0) {
3152      int i, myargc;
3153      i=fork();
3154      if (i) {
3155        /* parent set the child's pid */
3156        owl_global_set_newmsgproc_pid(&g, i);
3157        owl_function_debugmsg("I'm the parent and I started a new newmsgproc with pid %i", i);
3158      } else {
3159        /* child exec's the program */
3160        char **parsed;
3161        parsed=owl_parseline(owl_global_get_newmsgproc(&g), &myargc);
3162        if (myargc < 0) {
3163          owl_function_debugmsg("Could not parse newmsgproc '%s': unbalanced quotes?", owl_global_get_newmsgproc(&g));
3164        }
3165        if (myargc <= 0) {
3166          _exit(127);
3167        }
3168        parsed=owl_realloc(parsed, sizeof(*parsed) * (myargc+1));
3169        parsed[myargc] = NULL;
3170       
3171        owl_function_debugmsg("About to exec \"%s\" with %d arguments", parsed[0], myargc);
3172       
3173        execvp(parsed[0], parsed);
3174       
3175       
3176        /* was there an error exec'ing? */
3177        owl_function_debugmsg("Cannot run newmsgproc '%s': cannot exec '%s': %s", 
3178                              owl_global_get_newmsgproc(&g), parsed[0], strerror(errno));
3179        _exit(127);
3180      }
3181    }
3182  }
3183}
3184
3185/* print the xterm escape sequence to raise the window */
3186void owl_function_xterm_raise(void)
3187{
3188  printf("\033[5t");
3189}
3190
3191/* print the xterm escape sequence to deiconify the window */
3192void owl_function_xterm_deiconify(void)
3193{
3194  printf("\033[1t");
3195}
3196
3197/* Add the specified command to the startup file.  Eventually this
3198 * should be clever, and rewriting settings that will obviosly
3199 * override earlier settings with 'set' 'bindkey' and 'alias'
3200 * commands.  For now though we just remove any line that would
3201 * duplicate this one and then append this line to the end of
3202 * startupfile.
3203 */
3204void owl_function_addstartup(char *buff)
3205{
3206  FILE *file;
3207  char *filename;
3208
3209  filename=owl_global_get_startupfile(&g);
3210  file=fopen(filename, "a");
3211  if (!file) {
3212    owl_function_error("Error opening startupfile for new command");
3213    return;
3214  }
3215
3216  /* delete earlier copies */
3217  owl_util_file_deleteline(filename, buff, 1);
3218
3219  /* add this line */
3220  fprintf(file, "%s\n", buff);
3221
3222  fclose(file);
3223}
3224
3225/* Remove the specified command from the startup file. */
3226void owl_function_delstartup(char *buff)
3227{
3228  char *filename;
3229  filename=owl_global_get_startupfile(&g);
3230  owl_util_file_deleteline(filename, buff, 1);
3231}
3232
3233/* Execute owl commands from the given filename.  If the filename
3234 * is NULL, use the default owl startup commands file.
3235 */
3236void owl_function_source(char *filename)
3237{
3238  FILE *file;
3239  char buff[LINE];
3240
3241  if (!filename) {
3242    filename=owl_global_get_startupfile(&g);
3243    file=fopen(filename, "r");
3244  } else {
3245    file=fopen(filename, "r");
3246  }
3247  if (!file) {
3248    owl_function_error("Error opening file: %s", filename);
3249    return;
3250  }
3251  while (fgets(buff, LINE, file)!=NULL) {
3252    if (buff[0] == '#') continue;
3253    buff[strlen(buff)-1]='\0';
3254    owl_function_command(buff);
3255  }
3256  fclose(file);
3257}
3258
3259void owl_function_change_style(owl_view *v, char *stylename)
3260{
3261  owl_style *s;
3262
3263  s=owl_global_get_style_by_name(&g, stylename);
3264  if (!s) {
3265    owl_function_error("No style named %s", stylename);
3266    return;
3267  }
3268  owl_view_set_style(v, s);
3269  owl_messagelist_invalidate_formats(owl_global_get_msglist(&g));
3270  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
3271  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3272}
3273
3274void owl_function_toggleoneline()
3275{
3276  owl_view *v;
3277  owl_style *s;
3278
3279  v=owl_global_get_current_view(&g);
3280  s=owl_view_get_style(v);
3281
3282  if (!owl_style_matches_name(s, "oneline")) {
3283    owl_function_change_style(v, "oneline");
3284  } else {
3285    owl_function_change_style(v, owl_global_get_default_style(&g));
3286  }
3287
3288  owl_messagelist_invalidate_formats(owl_global_get_msglist(&g));
3289  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
3290  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3291}
3292
3293void owl_function_error(char *fmt, ...)
3294{
3295  va_list ap;
3296  char buff[2048], buff2[2048];
3297  char *date;
3298  time_t now;
3299
3300  now=time(NULL);
3301  date=owl_strdup(ctime(&now));
3302  date[strlen(date)-1]='\0';
3303
3304  va_start(ap, fmt);
3305
3306  vsnprintf(buff, 2048, fmt, ap);
3307  sprintf(buff2, "%s %s", date, buff);
3308  owl_function_debugmsg("ERROR: %s", buff);
3309  if (owl_global_get_curs_msgwin(&g)) {
3310    werase(owl_global_get_curs_msgwin(&g));
3311    waddstr(owl_global_get_curs_msgwin(&g), buff); 
3312    wnoutrefresh(owl_global_get_curs_msgwin(&g));
3313    owl_global_set_needrefresh(&g);
3314  }
3315  owl_errqueue_append_err(owl_global_get_errqueue(&g), buff2);
3316  va_end(ap);
3317  owl_free(date);
3318}
3319
3320void owl_function_showerrs()
3321{
3322  owl_fmtext fm;
3323
3324  owl_fmtext_init_null(&fm);
3325  owl_fmtext_append_normal(&fm, "Errors:\n\n");
3326  owl_errqueue_to_fmtext(owl_global_get_errqueue(&g), &fm);
3327  owl_function_popless_fmtext(&fm);
3328}
3329
3330void owl_function_makemsg(char *fmt, ...)
3331{
3332  va_list ap;
3333  char buff[2048];
3334
3335  if (!owl_global_get_curs_msgwin(&g)) return;
3336
3337  va_start(ap, fmt);
3338  werase(owl_global_get_curs_msgwin(&g));
3339 
3340  vsnprintf(buff, 2048, fmt, ap);
3341  owl_function_debugmsg("makemsg: %s", buff);
3342  waddstr(owl_global_get_curs_msgwin(&g), buff); 
3343  wnoutrefresh(owl_global_get_curs_msgwin(&g));
3344  owl_global_set_needrefresh(&g);
3345  va_end(ap);
3346}
3347
3348/* get locations for everyone in .anyone.  If 'notify' is '1' then
3349 * send a pseudo login or logout message for everyone not in sync with
3350 * the global zephyr buddy list.  The list is updated regardless of
3351 * the status of 'notify'.
3352 */
3353void owl_function_zephyr_buddy_check(int notify)
3354{
3355#ifdef HAVE_LIBZEPHYR
3356  int i, j;
3357  owl_list anyone;
3358  owl_message *m;
3359  owl_zbuddylist *zbl;
3360  char *user;
3361  ZLocations_t location[200];
3362  int numlocs, ret;
3363
3364  zbl=owl_global_get_zephyr_buddylist(&g);
3365
3366  owl_list_create(&anyone);
3367  ret=owl_zephyr_get_anyone_list(&anyone, NULL);
3368
3369  j=owl_list_get_size(&anyone);
3370  for (i=0; i<j; i++) {
3371    user=owl_list_get_element(&anyone, i);
3372    ret=ZLocateUser(user, &numlocs, ZAUTH);
3373    if (ret!=ZERR_NONE) {
3374      owl_function_error("Error getting location for %s", user);
3375      continue;
3376    }
3377    numlocs=200;
3378    ret=ZGetLocations(location, &numlocs);
3379    if (ret==0) {
3380      if ((numlocs>0) && !owl_zbuddylist_contains_user(zbl, user)) {
3381        /* Send a PSEUDO LOGIN! */
3382        if (notify) {
3383          m=owl_malloc(sizeof(owl_message));
3384          owl_message_create_pseudo_zlogin(m, 0, user, location[0].host, location[0].time, location[0].tty);
3385          owl_global_messagequeue_addmsg(&g, m);
3386        }
3387        owl_zbuddylist_adduser(zbl, user);
3388        owl_function_debugmsg("owl_function_zephyr_buddy_check: login for %s ", user);
3389      } else if ((numlocs==0) && owl_zbuddylist_contains_user(zbl, user)) {
3390        /* I don't think this ever happens (if there are 0 locations we should get an error from
3391         * ZGetLocations)
3392         */
3393        owl_function_error("owl_function_zephyr_buddy_check: exceptional case logout for %s ",user);
3394      }
3395    } else if ((ret==ZERR_NOLOCATIONS) && owl_zbuddylist_contains_user(zbl, user)) {
3396      /* Send a PSEUDO LOGOUT! */
3397      if (notify) {
3398        m=owl_malloc(sizeof(owl_message));
3399        owl_message_create_pseudo_zlogin(m, 1, user, "", "", "");
3400        owl_global_messagequeue_addmsg(&g, m);
3401      }
3402      owl_zbuddylist_deluser(zbl, user);
3403      owl_function_debugmsg("owl_function_zephyr_buddy_check: logout for %s ",user);
3404    }
3405  }
3406
3407  owl_list_free_all(&anyone, owl_free);
3408#endif
3409}
3410
3411void owl_function_aimsearch_results(char *email, owl_list *namelist)
3412{
3413  owl_fmtext fm;
3414  int i, j;
3415
3416  owl_fmtext_init_null(&fm);
3417  owl_fmtext_append_normal(&fm, "AIM screennames associated with ");
3418  owl_fmtext_append_normal(&fm, email);
3419  owl_fmtext_append_normal(&fm, ":\n");
3420
3421  j=owl_list_get_size(namelist);
3422  for (i=0; i<j; i++) {
3423    owl_fmtext_append_normal(&fm, "  ");
3424    owl_fmtext_append_normal(&fm, owl_list_get_element(namelist, i));
3425    owl_fmtext_append_normal(&fm, "\n");
3426  }
3427
3428  owl_function_popless_fmtext(&fm);
3429  owl_fmtext_free(&fm);
3430}
3431
3432int owl_function_get_color_count()
3433{
3434     return COLORS;
3435}
Note: See TracBrowser for help on using the repository browser.