source: functions.c @ a352335c

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