source: functions.c @ c3acb0b

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