source: functions.c @ c045455

barnowl_perlaimdebianowlrelease-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since c045455 was 3ba3af0, checked in by James M. Kretchmar <kretch@mit.edu>, 18 years ago
Better formatting for idle time in buddy list
  • Property mode set to 100644
File size: 81.8 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
1687  start=owl_global_get_starttime(&g);
1688
1689  sprintf(buff, "Version: %s\n", OWL_VERSION_STRING);
1690  sprintf(buff, "%sScreen size: %i lines, %i columns\n", buff, owl_global_get_lines(&g), owl_global_get_cols(&g));
1691  sprintf(buff, "%sStartup Arugments: %s\n", buff, owl_global_get_startupargs(&g));
1692  sprintf(buff, "%sStartup Time: %s", buff, ctime(&start));
1693
1694  up=owl_global_get_runtime(&g);
1695  days=up/86400;
1696  up-=days*86400;
1697  hours=up/3600;
1698  up-=hours*3600;
1699  minutes=up/60;
1700  up-=minutes*60;
1701  sprintf(buff, "%sRun Time: %i days %2.2i:%2.2i:%2.2i\n", buff, days, hours, minutes, up);
1702
1703  if (owl_global_get_hascolors(&g)) {
1704    sprintf(buff, "%sColor: Yes, %i color pairs.\n", buff, owl_global_get_colorpairs(&g));
1705  } else {
1706    strcat(buff, "Color: No.\n");
1707  }
1708
1709  sprintf(buff, "%sMemory Malloced: %i\n", buff, owl_global_get_malloced(&g));
1710  sprintf(buff, "%sMemory Freed: %i\n", buff, owl_global_get_freed(&g));
1711  sprintf(buff, "%sMemory In Use: %i\n", buff, owl_global_get_meminuse(&g));
1712
1713  owl_function_popless_text(buff);
1714}
1715
1716void owl_function_show_term()
1717{
1718  owl_fmtext fm;
1719  char buff[LINE];
1720
1721  owl_fmtext_init_null(&fm);
1722  sprintf(buff, "Terminal Lines: %i\nTerminal Columns: %i\n",
1723          owl_global_get_lines(&g),
1724          owl_global_get_cols(&g));
1725  owl_fmtext_append_normal(&fm, buff);
1726
1727  if (owl_global_get_hascolors(&g)) {
1728    owl_fmtext_append_normal(&fm, "Color: Yes\n");
1729    sprintf(buff, "Number of color pairs: %i\n", owl_global_get_colorpairs(&g));
1730    owl_fmtext_append_normal(&fm, buff);
1731    sprintf(buff, "Can change colors: %s\n", can_change_color() ? "yes" : "no");
1732    owl_fmtext_append_normal(&fm, buff);
1733  } else {
1734    owl_fmtext_append_normal(&fm, "Color: No\n");
1735  }
1736
1737  owl_function_popless_fmtext(&fm);
1738  owl_fmtext_free(&fm);
1739}
1740
1741
1742/* if type = 0 then normal reply.
1743 * if type = 1 then it's a reply to sender
1744 * if enter = 0 then allow the command to be edited
1745 * if enter = 1 then don't wait for editing
1746 */
1747void owl_function_reply(int type, int enter)
1748{
1749  char *buff=NULL, *oldbuff;
1750  owl_message *m;
1751  owl_filter *f;
1752 
1753  if (owl_view_get_size(owl_global_get_current_view(&g))==0) {
1754    owl_function_makemsg("No message selected");
1755  } else {
1756    char *class, *inst, *to, *cc=NULL;
1757   
1758    m=owl_view_get_element(owl_global_get_current_view(&g), owl_global_get_curmsg(&g));
1759    if (!m) {
1760      owl_function_makemsg("No message selected");
1761      return;
1762    }
1763
1764    /* first check if we catch the reply-lockout filter */
1765    f=owl_global_get_filter(&g, "reply-lockout");
1766    if (f) {
1767      if (owl_filter_message_match(f, m)) {
1768        owl_function_makemsg("Sorry, replies to this message have been disabled by the reply-lockout filter");
1769        return;
1770      }
1771    }
1772
1773    /* admin */
1774    if (owl_message_is_type_admin(m)) {
1775      owl_function_makemsg("You cannot reply to an admin message");
1776      return;
1777    }
1778
1779    /* zephyr */
1780    if (owl_message_is_type_zephyr(m)) {
1781      /* if it's a zephyr we sent, send it out the same way again */
1782      if (owl_message_is_direction_out(m)) {
1783        owl_function_zwrite_setup(owl_message_get_zwriteline(m));
1784        owl_global_set_buffercommand(&g, owl_message_get_zwriteline(m));
1785        return;
1786      }
1787
1788      /* Special case a personal reply to a webzephyr user on a class */
1789      if ((type==1) && !strcasecmp(owl_message_get_opcode(m), OWL_WEBZEPHYR_OPCODE)) {
1790        class=OWL_WEBZEPHYR_CLASS;
1791        inst=owl_message_get_sender(m);
1792        to=OWL_WEBZEPHYR_PRINCIPAL;
1793      } else if (!strcasecmp(owl_message_get_class(m), OWL_WEBZEPHYR_CLASS) && owl_message_is_loginout(m)) {
1794        /* Special case LOGIN/LOGOUT notifications on class "webzephyr" */
1795        class=OWL_WEBZEPHYR_CLASS;
1796        inst=owl_message_get_instance(m);
1797        to=OWL_WEBZEPHYR_PRINCIPAL;
1798      } else if (owl_message_is_loginout(m)) {
1799        /* Normal LOGIN/LOGOUT messages */
1800        class="MESSAGE";
1801        inst="PERSONAL";
1802        to=owl_message_get_sender(m);
1803      } else if (type==1) {
1804        /* Personal reply */
1805        class="MESSAGE";
1806        inst="PERSONAL";
1807        to=owl_message_get_sender(m);
1808      } else {
1809        /* General reply */
1810        class=owl_message_get_class(m);
1811        inst=owl_message_get_instance(m);
1812        to=owl_message_get_recipient(m);
1813        cc=owl_message_get_cc(m);
1814        if (!strcmp(to, "") || !strcmp(to, "*")) {
1815          to="";
1816        } else if (to[0]=='@') {
1817          /* leave it, to get the realm */
1818        } else {
1819          to=owl_message_get_sender(m);
1820        }
1821      }
1822       
1823      /* create the command line */
1824      if (!strcasecmp(owl_message_get_opcode(m), "CRYPT")) {
1825        buff=owl_strdup("zcrypt");
1826      } else {
1827        buff = owl_strdup("zwrite");
1828      }
1829      if (strcasecmp(class, "message")) {
1830        buff = owl_sprintf("%s -c %s%s%s", oldbuff=buff, owl_getquoting(class), class, owl_getquoting(class));
1831        owl_free(oldbuff);
1832      }
1833      if (strcasecmp(inst, "personal")) {
1834        buff = owl_sprintf("%s -i %s%s%s", oldbuff=buff, owl_getquoting(inst), inst, owl_getquoting(inst));
1835        owl_free(oldbuff);
1836      }
1837      if (*to != '\0') {
1838        char *tmp, *oldtmp, *tmp2;
1839        tmp=short_zuser(to);
1840        if (cc) {
1841          tmp = owl_util_uniq(oldtmp=tmp, cc, "-");
1842          owl_free(oldtmp);
1843          buff = owl_sprintf("%s -C %s", oldbuff=buff, tmp);
1844          owl_free(oldbuff);
1845        } else {
1846          if (owl_global_is_smartstrip(&g)) {
1847            tmp2=tmp;
1848            tmp=owl_util_smartstripped_user(tmp2);
1849            owl_free(tmp2);
1850          }
1851          buff = owl_sprintf("%s %s", oldbuff=buff, tmp);
1852          owl_free(oldbuff);
1853        }
1854        owl_free(tmp);
1855      }
1856      if (cc) owl_free(cc);
1857    }
1858
1859    /* aim */
1860    if (owl_message_is_type_aim(m)) {
1861      if (owl_message_is_direction_out(m)) {
1862        buff=owl_sprintf("aimwrite %s", owl_message_get_recipient(m));
1863      } else {
1864        buff=owl_sprintf("aimwrite %s", owl_message_get_sender(m));
1865      }
1866    }
1867   
1868    if (enter) {
1869      owl_history *hist = owl_global_get_cmd_history(&g);
1870      owl_history_store(hist, buff);
1871      owl_history_reset(hist);
1872      owl_function_command_norv(buff);
1873    } else {
1874      owl_function_start_command(buff);
1875    }
1876    owl_free(buff);
1877  }
1878}
1879
1880void owl_function_zlocate(int argc, char **argv, int auth)
1881{
1882  owl_fmtext fm;
1883  char *ptr, buff[LINE];
1884  int i;
1885
1886  owl_fmtext_init_null(&fm);
1887
1888  for (i=0; i<argc; i++) {
1889    ptr=long_zuser(argv[i]);
1890    owl_zephyr_zlocate(ptr, buff, auth);
1891    owl_fmtext_append_normal(&fm, buff);
1892    owl_free(ptr);
1893  }
1894
1895  owl_function_popless_fmtext(&fm);
1896  owl_fmtext_free(&fm);
1897}
1898
1899void owl_function_start_command(char *line)
1900{
1901  int i, j;
1902  owl_editwin *tw;
1903
1904  tw=owl_global_get_typwin(&g);
1905  owl_global_set_typwin_active(&g);
1906  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, 
1907                        owl_global_get_cmd_history(&g));
1908
1909  owl_editwin_set_locktext(tw, "command: ");
1910  owl_global_set_needrefresh(&g);
1911
1912  j=strlen(line);
1913  for (i=0; i<j; i++) {
1914    owl_editwin_process_char(tw, line[i]);
1915  }
1916  owl_editwin_redisplay(tw, 0);
1917
1918  owl_context_set_editline(owl_global_get_context(&g), tw);
1919  owl_function_activate_keymap("editline");
1920   
1921}
1922
1923void owl_function_start_question(char *line)
1924{
1925  owl_editwin *tw;
1926
1927  tw=owl_global_get_typwin(&g);
1928  owl_global_set_typwin_active(&g);
1929  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, owl_global_get_cmd_history(&g));
1930
1931  owl_editwin_set_locktext(tw, line);
1932  owl_global_set_needrefresh(&g);
1933
1934  owl_editwin_redisplay(tw, 0);
1935
1936  owl_context_set_editresponse(owl_global_get_context(&g), tw);
1937  owl_function_activate_keymap("editresponse");
1938}
1939
1940void owl_function_start_password(char *line)
1941{
1942  owl_editwin *tw;
1943
1944  tw=owl_global_get_typwin(&g);
1945  owl_global_set_typwin_active(&g);
1946  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, owl_global_get_cmd_history(&g));
1947  owl_editwin_set_echochar(tw, '*');
1948
1949  owl_editwin_set_locktext(tw, line);
1950  owl_global_set_needrefresh(&g);
1951
1952  owl_editwin_redisplay(tw, 0);
1953
1954  owl_context_set_editresponse(owl_global_get_context(&g), tw);
1955  owl_function_activate_keymap("editresponse");
1956}
1957
1958char *owl_function_exec(int argc, char **argv, char *buff, int type)
1959{
1960  /* if type == 1 display in a popup
1961   * if type == 2 display an admin messages
1962   * if type == 0 return output
1963   * else display in a popup
1964   */
1965  char *newbuff, *redirect = " 2>&1 < /dev/null";
1966  char *out, buff2[1024];
1967  int size;
1968  FILE *p;
1969
1970  if (argc<2) {
1971    owl_function_makemsg("Wrong number of arguments to the exec command");
1972    return NULL;
1973  }
1974
1975  buff = skiptokens(buff, 1);
1976  newbuff = owl_malloc(strlen(buff)+strlen(redirect)+1);
1977  strcpy(newbuff, buff);
1978  strcat(newbuff, redirect);
1979
1980  p=popen(newbuff, "r");
1981  out=owl_malloc(1024);
1982  size=1024;
1983  strcpy(out, "");
1984  while (fgets(buff2, 1024, p)!=NULL) {
1985    size+=1024;
1986    out=owl_realloc(out, size);
1987    strcat(out, buff2);
1988  }
1989  pclose(p);
1990
1991  if (type==1) {
1992    owl_function_popless_text(out);
1993  } else if (type==0) {
1994    return out;
1995  } else if (type==2) {
1996    owl_function_adminmsg(buff, out);
1997  } else {
1998    owl_function_popless_text(out);
1999  }
2000  owl_free(out);
2001  return NULL;
2002}
2003
2004
2005char *owl_function_perl(int argc, char **argv, char *buff, int type)
2006{
2007  /* if type == 1 display in a popup
2008   * if type == 2 display an admin messages
2009   * if type == 0 return output
2010   * else display in a popup
2011   */
2012  char *perlout;
2013
2014  if (argc<2) {
2015    owl_function_makemsg("Wrong number of arguments to perl command");
2016    return NULL;
2017  }
2018
2019  /* consume first token (argv[0]) */
2020  buff = skiptokens(buff, 1);
2021
2022  perlout = owl_config_execute(buff);
2023  if (perlout) { 
2024    if (type==1) {
2025      owl_function_popless_text(perlout);
2026    } else if (type==2) {
2027      owl_function_adminmsg(buff, perlout);
2028    } else if (type==0) {
2029      return perlout;
2030    } else {
2031      owl_function_popless_text(perlout);
2032    }
2033    owl_free(perlout);
2034  }
2035  return NULL;
2036}
2037
2038#if 0
2039void owl_function_change_view_old(char *filtname)
2040{
2041  owl_view *v;
2042  owl_filter *f;
2043  int curid=-1, newpos, curmsg;
2044  owl_message *curm=NULL;
2045
2046  v=owl_global_get_current_view(&g);
2047  curmsg=owl_global_get_curmsg(&g);
2048  if (curmsg==-1) {
2049    owl_function_debugmsg("Hit the curmsg==-1 case in change_view");
2050  } else {
2051    curm=owl_view_get_element(v, curmsg);
2052    if (curm) {
2053      curid=owl_message_get_id(curm);
2054      owl_view_save_curmsgid(v, curid);
2055    }
2056  }
2057
2058  /* grab the filter */;
2059  f=owl_global_get_filter(&g, filtname);
2060  if (!f) {
2061    owl_function_makemsg("Unknown filter");
2062    return;
2063  }
2064
2065  /* free the existing view and create a new one based on the filter */
2066  owl_view_free(v);
2067  owl_view_create(v, f);
2068
2069  /* Figure out what to set the current message to.
2070   * - If the view we're leaving has messages in it, go to the closest message
2071   *   to the last message pointed to in that view.
2072   * - If the view we're leaving is empty, try to restore the position
2073   *   from the last time we were in the new view.  */
2074  if (curm) {
2075    newpos = owl_view_get_nearest_to_msgid(v, curid);
2076  } else {
2077    newpos = owl_view_get_nearest_to_saved(v);
2078  }
2079
2080  owl_global_set_curmsg(&g, newpos);
2081
2082  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
2083  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2084  owl_global_set_direction_downwards(&g);
2085}
2086#endif
2087
2088void owl_function_change_view(char *filtname)
2089{
2090  owl_view *v;
2091  owl_filter *f;
2092  int curid=-1, newpos, curmsg;
2093  owl_message *curm=NULL;
2094
2095  v=owl_global_get_current_view(&g);
2096
2097  curmsg=owl_global_get_curmsg(&g);
2098  if (curmsg==-1) {
2099    owl_function_debugmsg("Hit the curmsg==-1 case in change_view");
2100  } else {
2101    curm=owl_view_get_element(v, curmsg);
2102    if (curm) {
2103      curid=owl_message_get_id(curm);
2104      owl_view_save_curmsgid(v, curid);
2105    }
2106  }
2107
2108  f=owl_global_get_filter(&g, filtname);
2109  if (!f) {
2110    owl_function_makemsg("Unknown filter");
2111    return;
2112  }
2113
2114  owl_view_new_filter(v, f);
2115
2116  /* Figure out what to set the current message to.
2117   * - If the view we're leaving has messages in it, go to the closest message
2118   *   to the last message pointed to in that view.
2119   * - If the view we're leaving is empty, try to restore the position
2120   *   from the last time we were in the new view.  */
2121  if (curm) {
2122    newpos = owl_view_get_nearest_to_msgid(v, curid);
2123  } else {
2124    newpos = owl_view_get_nearest_to_saved(v);
2125  }
2126
2127  owl_global_set_curmsg(&g, newpos);
2128  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
2129  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2130  owl_global_set_direction_downwards(&g);
2131}
2132
2133void owl_function_create_filter(int argc, char **argv)
2134{
2135  owl_filter *f;
2136  owl_view *v;
2137  int ret, inuse=0;
2138
2139  if (argc < 2) {
2140    owl_function_makemsg("Wrong number of arguments to filter command");
2141    return;
2142  }
2143
2144  v=owl_global_get_current_view(&g);
2145
2146  /* don't touch the all filter */
2147  if (!strcmp(argv[1], "all")) {
2148    owl_function_makemsg("You may not change the 'all' filter.");
2149    return;
2150  }
2151
2152  /* deal with the case of trying change the filter color */
2153  if (argc==4 && !strcmp(argv[2], "-c")) {
2154    f=owl_global_get_filter(&g, argv[1]);
2155    if (!f) {
2156      owl_function_makemsg("The filter '%s' does not exist.", argv[1]);
2157      return;
2158    }
2159    owl_filter_set_color(f, owl_util_string_to_color(argv[3]));
2160    owl_global_set_needrefresh(&g);
2161    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2162    return;
2163  }
2164
2165  /* create the filter and check for errors */
2166  f=owl_malloc(sizeof(owl_filter));
2167  ret=owl_filter_init(f, argv[1], argc-2, argv+2);
2168  if (ret==-1) {
2169    owl_free(f);
2170    owl_function_makemsg("Invalid filter syntax");
2171    return;
2172  }
2173
2174  /* if the named filter is in use by the current view, remember it */
2175  if (!strcmp(owl_view_get_filtname(v), argv[1])) {
2176    inuse=1;
2177  }
2178
2179  /* if the named filter already exists, nuke it */
2180  if (owl_global_get_filter(&g, argv[1])) {
2181    owl_global_remove_filter(&g, argv[1]);
2182  }
2183
2184  /* add the filter */
2185  owl_global_add_filter(&g, f);
2186
2187  /* if it was in use by the current view then update */
2188  if (inuse) {
2189    owl_function_change_view(argv[1]);
2190  }
2191  owl_global_set_needrefresh(&g);
2192  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2193}
2194
2195void owl_function_show_filters()
2196{
2197  owl_list *l;
2198  owl_filter *f;
2199  int i, j;
2200  owl_fmtext fm;
2201
2202  owl_fmtext_init_null(&fm);
2203
2204  l=owl_global_get_filterlist(&g);
2205  j=owl_list_get_size(l);
2206
2207  owl_fmtext_append_bold(&fm, "Filters:\n");
2208
2209  for (i=0; i<j; i++) {
2210    f=owl_list_get_element(l, i);
2211    owl_fmtext_append_normal(&fm, "   ");
2212    if (owl_global_get_hascolors(&g)) {
2213      owl_fmtext_append_normal_color(&fm, owl_filter_get_name(f), owl_filter_get_color(f));
2214    } else {
2215      owl_fmtext_append_normal(&fm, owl_filter_get_name(f));
2216    }
2217    owl_fmtext_append_normal(&fm, "\n");
2218  }
2219  owl_function_popless_fmtext(&fm);
2220  owl_fmtext_free(&fm);
2221}
2222
2223void owl_function_show_filter(char *name)
2224{
2225  owl_filter *f;
2226  char buff[5000];
2227
2228  f=owl_global_get_filter(&g, name);
2229  if (!f) {
2230    owl_function_makemsg("There is no filter with that name");
2231    return;
2232  }
2233  owl_filter_print(f, buff);
2234  owl_function_popless_text(buff);
2235}
2236
2237void owl_function_show_zpunts()
2238{
2239  owl_filter *f;
2240  owl_list *fl;
2241  char buff[5000];
2242  owl_fmtext fm;
2243  int i, j;
2244
2245  owl_fmtext_init_null(&fm);
2246
2247  fl=owl_global_get_puntlist(&g);
2248  j=owl_list_get_size(fl);
2249  owl_fmtext_append_bold(&fm, "Active zpunt filters:\n");
2250
2251  for (i=0; i<j; i++) {
2252    f=owl_list_get_element(fl, i);
2253    owl_filter_print(f, buff);
2254    owl_fmtext_append_normal(&fm, buff);
2255  }
2256  owl_function_popless_fmtext(&fm);
2257  owl_fmtext_free(&fm);
2258}
2259
2260/* Create a filter for a class, instance if one doesn't exist.  If
2261 * instance is NULL then catch all messgaes in the class.  Returns the
2262 * name of the filter, which the caller must free.
2263 */
2264char *owl_function_classinstfilt(char *class, char *instance) 
2265{
2266  owl_list *fl;
2267  owl_filter *f;
2268  char *argbuff, *filtname;
2269  char *tmpclass, *tmpinstance = NULL;
2270  int len;
2271
2272  fl=owl_global_get_filterlist(&g);
2273
2274  /* name for the filter */
2275  len=strlen(class)+30;
2276  if (instance) len+=strlen(instance);
2277  filtname=owl_malloc(len);
2278  if (!instance) {
2279    sprintf(filtname, "class-%s", class);
2280  } else {
2281    sprintf(filtname, "class-%s-instance-%s", class, instance);
2282  }
2283  /* downcase it */
2284  downstr(filtname);
2285  /* turn spaces into hyphens */
2286  owl_util_tr(filtname, ' ', '.');
2287 
2288  /* if it already exists then go with it.  This lets users override */
2289  if (owl_global_get_filter(&g, filtname)) {
2290    return(filtname);
2291  }
2292
2293  /* create the new filter */
2294  argbuff=owl_malloc(len+20);
2295  tmpclass=owl_strdup(class);
2296  owl_util_tr(tmpclass, ' ', '.');
2297  if (instance) {
2298    tmpinstance=owl_strdup(instance);
2299    owl_util_tr(tmpinstance, ' ', '.');
2300  }
2301  sprintf(argbuff, "( class ^%s$ )", tmpclass);
2302  if (tmpinstance) {
2303    sprintf(argbuff, "%s and ( instance ^%s$ )", argbuff, tmpinstance);
2304  }
2305  owl_free(tmpclass);
2306  if (tmpinstance) owl_free(tmpinstance);
2307
2308  f=owl_malloc(sizeof(owl_filter));
2309  owl_filter_init_fromstring(f, filtname, argbuff);
2310
2311  /* add it to the global list */
2312  owl_global_add_filter(&g, f);
2313
2314  owl_free(argbuff);
2315  return(filtname);
2316}
2317
2318/* Create a filter for personal zephyrs to or from the specified
2319 * zephyr user.  Includes login/logout notifications for the user.
2320 * The name of the filter will be 'user-<user>'.  If a filter already
2321 * exists with this name, no new filter will be created.  This allows
2322 * the configuration to override this function.  Returns the name of
2323 * the filter, which the caller must free.
2324 */
2325char *owl_function_zuserfilt(char *user)
2326{
2327  owl_filter *f;
2328  char *argbuff, *longuser, *shortuser, *filtname;
2329
2330  /* stick the local realm on if it's not there */
2331  longuser=long_zuser(user);
2332  shortuser=short_zuser(user);
2333
2334  /* name for the filter */
2335  filtname=owl_malloc(strlen(shortuser)+20);
2336  sprintf(filtname, "user-%s", shortuser);
2337
2338  /* if it already exists then go with it.  This lets users override */
2339  if (owl_global_get_filter(&g, filtname)) {
2340    return(owl_strdup(filtname));
2341  }
2342
2343  /* create the new-internal filter */
2344  f=owl_malloc(sizeof(owl_filter));
2345
2346  argbuff=owl_malloc(strlen(longuser)+1000);
2347  sprintf(argbuff, "( type ^zephyr$ and ( class ^message$ and instance ^personal$ and ");
2348  sprintf(argbuff, "%s ( ( direction ^in$ and sender ^%s$ ) or ( direction ^out$ and recipient ^%s$ ) ) )", argbuff, longuser, longuser);
2349  sprintf(argbuff, "%s or ( ( class ^login$ ) and ( sender ^%s$ ) ) )", argbuff, longuser);
2350
2351  owl_filter_init_fromstring(f, filtname, argbuff);
2352
2353  /* add it to the global list */
2354  owl_global_add_filter(&g, f);
2355
2356  /* free stuff */
2357  owl_free(argbuff);
2358  owl_free(longuser);
2359  owl_free(shortuser);
2360
2361  return(filtname);
2362}
2363
2364/* Create a filter for AIM IM messages to or from the specified
2365 * screenname.  The name of the filter will be 'aimuser-<user>'.  If a
2366 * filter already exists with this name, no new filter will be
2367 * created.  This allows the configuration to override this function.
2368 * Returns the name of the filter, which the caller must free.
2369 */
2370char *owl_function_aimuserfilt(char *user)
2371{
2372  owl_filter *f;
2373  char *argbuff, *filtname;
2374
2375  /* name for the filter */
2376  filtname=owl_malloc(strlen(user)+40);
2377  sprintf(filtname, "aimuser-%s", user);
2378
2379  /* if it already exists then go with it.  This lets users override */
2380  if (owl_global_get_filter(&g, filtname)) {
2381    return(owl_strdup(filtname));
2382  }
2383
2384  /* create the new-internal filter */
2385  f=owl_malloc(sizeof(owl_filter));
2386
2387  argbuff=owl_malloc(1000);
2388  sprintf(argbuff,
2389          "( type ^aim$ and ( ( sender ^%s$ and recipient ^%s$ ) or ( sender ^%s$ and recipient ^%s$ ) ) )",
2390          user, owl_global_get_aim_screenname(&g), owl_global_get_aim_screenname(&g), user);
2391
2392  owl_filter_init_fromstring(f, filtname, argbuff);
2393
2394  /* add it to the global list */
2395  owl_global_add_filter(&g, f);
2396
2397  /* free stuff */
2398  owl_free(argbuff);
2399
2400  return(filtname);
2401}
2402
2403char *owl_function_typefilt(char *type)
2404{
2405  owl_filter *f;
2406  char *argbuff, *filtname;
2407
2408  /* name for the filter */
2409  filtname=owl_sprintf("type-%s", type);
2410
2411  /* if it already exists then go with it.  This lets users override */
2412  if (owl_global_get_filter(&g, filtname)) {
2413    return filtname;
2414  }
2415
2416  /* create the new-internal filter */
2417  f=owl_malloc(sizeof(owl_filter));
2418
2419  argbuff = owl_sprintf("type ^%s$", type);
2420
2421  owl_filter_init_fromstring(f, filtname, argbuff);
2422
2423  /* add it to the global list */
2424  owl_global_add_filter(&g, f);
2425
2426  /* free stuff */
2427  owl_free(argbuff);
2428
2429  return filtname;
2430}
2431
2432/* If flag is 1, marks for deletion.  If flag is 0,
2433 * unmarks for deletion. */
2434void owl_function_delete_curview_msgs(int flag)
2435{
2436  owl_view *v;
2437  int i, j;
2438
2439  v=owl_global_get_current_view(&g);
2440  j=owl_view_get_size(v);
2441  for (i=0; i<j; i++) {
2442    if (flag == 1) {
2443      owl_message_mark_delete(owl_view_get_element(v, i));
2444    } else if (flag == 0) {
2445      owl_message_unmark_delete(owl_view_get_element(v, i));
2446    }
2447  }
2448
2449  owl_function_makemsg("%i messages marked for %sdeletion", j, flag?"":"un");
2450
2451  owl_mainwin_redisplay(owl_global_get_mainwin(&g)); 
2452}
2453
2454/* Create a filter based on the current message.  Returns the name of
2455 * a filter or null.  The caller must free this name.
2456 *
2457 * if the curmsg is a personal zephyr return a filter name
2458 *    to the zephyr converstaion with that user.
2459 * If the curmsg is a zephyr class message, instance foo, recip *,
2460 *    return a filter name to the class, inst.
2461 * If the curmsg is a zephyr class message and type==0 then
2462 *    return a filter name for just the class.
2463 * If the curmsg is a zephyr class message and type==1 then
2464 *    return a filter name for the class and instance.
2465 * If the curmsg is a personal AIM message returna  filter
2466 *    name to the AIM conversation with that user
2467 */
2468char *owl_function_smartfilter(int type)
2469{
2470  owl_view *v;
2471  owl_message *m;
2472  char *zperson, *filtname=NULL;
2473 
2474  v=owl_global_get_current_view(&g);
2475  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2476
2477  if (!m || owl_view_get_size(v)==0) {
2478    owl_function_makemsg("No message selected\n");
2479    return(NULL);
2480  }
2481
2482  /* very simple handling of admin messages for now */
2483  if (owl_message_is_type_admin(m)) {
2484    return(owl_function_typefilt("admin"));
2485  }
2486
2487  /* aim messages */
2488  if (owl_message_is_type_aim(m)) {
2489    if (owl_message_is_direction_in(m)) {
2490      filtname=owl_function_aimuserfilt(owl_message_get_sender(m));
2491    } else if (owl_message_is_direction_out(m)) {
2492      filtname=owl_function_aimuserfilt(owl_message_get_recipient(m));
2493    }
2494    return(filtname);
2495  }
2496
2497  /* narrow personal and login messages to the sender or recip as appropriate */
2498  if (owl_message_is_personal(m) || owl_message_is_loginout(m)) {
2499    if (owl_message_is_type_zephyr(m)) {
2500      if (owl_message_is_direction_in(m)) {
2501        zperson=short_zuser(owl_message_get_sender(m));
2502      } else {
2503        zperson=short_zuser(owl_message_get_recipient(m));
2504      }
2505      filtname=owl_function_zuserfilt(zperson);
2506      owl_free(zperson);
2507      return(filtname);
2508    }
2509    return(NULL);
2510  }
2511
2512  /* narrow class MESSAGE, instance foo, recip * messages to class, inst */
2513  if (!strcasecmp(owl_message_get_class(m), "message") && !owl_message_is_personal(m)) {
2514    filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2515    return(filtname);
2516  }
2517
2518  /* otherwise narrow to the class */
2519  if (type==0) {
2520    filtname=owl_function_classinstfilt(owl_message_get_class(m), NULL);
2521  } else if (type==1) {
2522    filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2523  }
2524  return(filtname);
2525}
2526
2527void owl_function_smartzpunt(int type)
2528{
2529  /* Starts a zpunt command based on the current class,instance pair.
2530   * If type=0, uses just class.  If type=1, uses instance as well. */
2531  owl_view *v;
2532  owl_message *m;
2533  char *cmd, *cmdprefix, *mclass, *minst;
2534 
2535  v=owl_global_get_current_view(&g);
2536  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2537
2538  if (!m || owl_view_get_size(v)==0) {
2539    owl_function_makemsg("No message selected\n");
2540    return;
2541  }
2542
2543  /* for now we skip admin messages. */
2544  if (owl_message_is_type_admin(m)
2545      || owl_message_is_loginout(m)
2546      || !owl_message_is_type_zephyr(m)) {
2547    owl_function_makemsg("smartzpunt doesn't support this message type.");
2548    return;
2549  }
2550
2551  mclass = owl_message_get_class(m);
2552  minst = owl_message_get_instance(m);
2553  if (!mclass || !*mclass || *mclass==' '
2554      || (!strcasecmp(mclass, "message") && !strcasecmp(minst, "personal"))
2555      || (type && (!minst || !*minst|| *minst==' '))) {
2556    owl_function_makemsg("smartzpunt can't safely do this for <%s,%s>",
2557                         mclass, minst);
2558  } else {
2559    cmdprefix = "start-command zpunt ";
2560    cmd = owl_malloc(strlen(cmdprefix)+strlen(mclass)+strlen(minst)+3);
2561    strcpy(cmd, cmdprefix);
2562    strcat(cmd, mclass);
2563    if (type) {
2564      strcat(cmd, " ");
2565      strcat(cmd, minst);
2566    } else {
2567      strcat(cmd, " *");
2568    }
2569    owl_function_command(cmd);
2570    owl_free(cmd);
2571  }
2572}
2573
2574
2575
2576void owl_function_color_current_filter(char *color)
2577{
2578  owl_filter *f;
2579  char *name;
2580
2581  name=owl_view_get_filtname(owl_global_get_current_view(&g));
2582  f=owl_global_get_filter(&g, name);
2583  if (!f) {
2584    owl_function_makemsg("Unknown filter");
2585    return;
2586  }
2587
2588  /* don't touch the all filter */
2589  if (!strcmp(name, "all")) {
2590    owl_function_makemsg("You may not change the 'all' filter.");
2591    return;
2592  }
2593
2594  /* deal with the case of trying change the filter color */
2595  owl_filter_set_color(f, owl_util_string_to_color(color));
2596  owl_global_set_needrefresh(&g);
2597  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2598}
2599
2600void owl_function_show_colors()
2601{
2602  owl_fmtext fm;
2603
2604  owl_fmtext_init_null(&fm);
2605  owl_fmtext_append_normal_color(&fm, "default\n", OWL_COLOR_DEFAULT);
2606  owl_fmtext_append_normal_color(&fm, "red\n", OWL_COLOR_RED);
2607  owl_fmtext_append_normal_color(&fm, "green\n", OWL_COLOR_GREEN);
2608  owl_fmtext_append_normal_color(&fm, "yellow\n", OWL_COLOR_YELLOW);
2609  owl_fmtext_append_normal_color(&fm, "blue\n", OWL_COLOR_BLUE);
2610  owl_fmtext_append_normal_color(&fm, "magenta\n", OWL_COLOR_MAGENTA);
2611  owl_fmtext_append_normal_color(&fm, "cyan\n", OWL_COLOR_CYAN);
2612  owl_fmtext_append_normal_color(&fm, "white\n", OWL_COLOR_WHITE);
2613
2614  owl_function_popless_fmtext(&fm);
2615  owl_fmtext_free(&fm);
2616}
2617
2618/* add the given class, inst, recip to the punt list for filtering.
2619 *   if direction==0 then punt
2620 *   if direction==1 then unpunt
2621 */
2622void owl_function_zpunt(char *class, char *inst, char *recip, int direction)
2623{
2624  owl_filter *f;
2625  owl_list *fl;
2626  char *buff;
2627  int ret, i, j;
2628
2629  fl=owl_global_get_puntlist(&g);
2630
2631  /* first, create the filter */
2632  f=malloc(sizeof(owl_filter));
2633  buff=malloc(strlen(class)+strlen(inst)+strlen(recip)+100);
2634  strcpy(buff, "class");
2635  if (!strcmp(class, "*")) {
2636    strcat(buff, " .*");
2637  } else {
2638    sprintf(buff, "%s ^%s$", buff, class);
2639  }
2640  if (!strcmp(inst, "*")) {
2641    strcat(buff, " and instance .*");
2642  } else {
2643    sprintf(buff, "%s and instance ^%s$", buff, inst);
2644  }
2645  if (strcmp(recip, "*")) {
2646    sprintf(buff, "%s and recipient ^%s$", buff, recip);
2647  }
2648 
2649  owl_function_debugmsg("About to filter %s", buff);
2650  ret=owl_filter_init_fromstring(f, "punt-filter", buff);
2651  owl_free(buff);
2652  if (ret) {
2653    owl_function_makemsg("Error creating filter for zpunt");
2654    owl_filter_free(f);
2655    return;
2656  }
2657
2658  /* Check for an identical filter */
2659  j=owl_list_get_size(fl);
2660  for (i=0; i<j; i++) {
2661    if (owl_filter_equiv(f, owl_list_get_element(fl, i))) {
2662      /* if we're punting, then just silently bow out on this duplicate */
2663      if (direction==0) {
2664        owl_filter_free(f);
2665        return;
2666      }
2667
2668      /* if we're unpunting, then remove this filter from the puntlist */
2669      if (direction==1) {
2670        owl_filter_free(owl_list_get_element(fl, i));
2671        owl_list_remove_element(fl, i);
2672        return;
2673      }
2674    }
2675  }
2676
2677  /* If we're punting, add the filter to the global punt list */
2678  if (direction==0) {
2679    owl_list_append_element(fl, f);
2680  }
2681}
2682
2683void owl_function_activate_keymap(char *keymap)
2684{
2685  if (!owl_keyhandler_activate(owl_global_get_keyhandler(&g), keymap)) {
2686    owl_function_makemsg("Unable to activate keymap '%s'", keymap);
2687  }
2688}
2689
2690
2691void owl_function_show_keymaps()
2692{
2693  owl_list l;
2694  owl_fmtext fm;
2695  owl_keymap *km;
2696  owl_keyhandler *kh;
2697  int i, numkm;
2698  char *kmname;
2699
2700  kh = owl_global_get_keyhandler(&g);
2701  owl_fmtext_init_null(&fm);
2702  owl_fmtext_append_bold(&fm, "Keymaps:   ");
2703  owl_fmtext_append_normal(&fm, "(use 'show keymap <name>' for details)\n");
2704  owl_keyhandler_get_keymap_names(kh, &l);
2705  owl_fmtext_append_list(&fm, &l, "\n", owl_function_keymap_summary);
2706  owl_fmtext_append_normal(&fm, "\n");
2707
2708  numkm = owl_list_get_size(&l);
2709  for (i=0; i<numkm; i++) {
2710    kmname = owl_list_get_element(&l, i);
2711    km = owl_keyhandler_get_keymap(kh, kmname);
2712    owl_fmtext_append_bold(&fm, "\n\n----------------------------------------------------------------------------------------------------\n\n");
2713    owl_keymap_get_details(km, &fm);   
2714  }
2715  owl_fmtext_append_normal(&fm, "\n");
2716 
2717  owl_function_popless_fmtext(&fm);
2718  owl_keyhandler_keymap_namelist_free(&l);
2719  owl_fmtext_free(&fm);
2720}
2721
2722char *owl_function_keymap_summary(void *name)
2723{
2724  owl_keymap *km
2725    = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
2726  if (km) return owl_keymap_summary(km);
2727  else return(NULL);
2728}
2729
2730/* TODO: implement for real */
2731void owl_function_show_keymap(char *name)
2732{
2733  owl_fmtext fm;
2734  owl_keymap *km;
2735
2736  owl_fmtext_init_null(&fm);
2737  km = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
2738  if (km) {
2739    owl_keymap_get_details(km, &fm);
2740  } else {
2741    owl_fmtext_append_normal(&fm, "No such keymap...\n");
2742  } 
2743  owl_function_popless_fmtext(&fm);
2744  owl_fmtext_free(&fm);
2745}
2746
2747void owl_function_help_for_command(char *cmdname)
2748{
2749  owl_fmtext fm;
2750
2751  owl_fmtext_init_null(&fm);
2752  owl_cmd_get_help(owl_global_get_cmddict(&g), cmdname, &fm);
2753  owl_function_popless_fmtext(&fm); 
2754  owl_fmtext_free(&fm);
2755}
2756
2757void owl_function_search_start(char *string, int direction)
2758{
2759  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
2760  owl_global_set_search_active(&g, string);
2761  owl_function_search_helper(0, direction);
2762}
2763
2764void owl_function_search_continue(int direction)
2765{
2766  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
2767  owl_function_search_helper(1, direction);
2768}
2769
2770void owl_function_search_helper(int mode, int direction)
2771{
2772  /* move to a message that contains the string.  If direction is
2773   * OWL_DIRECTION_DOWNWARDS then search fowards, if direction is
2774   * OWL_DIRECTION_UPWARDS then search backwards.
2775   *
2776   * If mode==0 then it will stay on the current message if it
2777   * contains the string.
2778   */
2779
2780  owl_view *v;
2781  int viewsize, i, curmsg, start;
2782  owl_message *m;
2783
2784  v=owl_global_get_current_view(&g);
2785  viewsize=owl_view_get_size(v);
2786  curmsg=owl_global_get_curmsg(&g);
2787 
2788  if (viewsize==0) {
2789    owl_function_makemsg("No messages present");
2790    return;
2791  }
2792
2793  if (mode==0) {
2794    start=curmsg;
2795  } else if (direction==OWL_DIRECTION_DOWNWARDS) {
2796    start=curmsg+1;
2797  } else {
2798    start=curmsg-1;
2799  }
2800
2801  /* bounds check */
2802  if (start>=viewsize || start<0) {
2803    owl_function_makemsg("No further matches found");
2804    return;
2805  }
2806
2807  for (i=start; i<viewsize && i>=0;) {
2808    m=owl_view_get_element(v, i);
2809    if (owl_message_search(m, owl_global_get_search_string(&g))) {
2810      owl_global_set_curmsg(&g, i);
2811      owl_function_calculate_topmsg(direction);
2812      owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2813      if (direction==OWL_DIRECTION_DOWNWARDS) {
2814        owl_global_set_direction_downwards(&g);
2815      } else {
2816        owl_global_set_direction_upwards(&g);
2817      }
2818      return;
2819    }
2820    if (direction==OWL_DIRECTION_DOWNWARDS) {
2821      i++;
2822    } else {
2823      i--;
2824    }
2825  }
2826  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2827  owl_function_makemsg("No matches found");
2828}
2829
2830
2831/* strips formatting from ztext and returns the unformatted text.
2832 * caller is responsible for freeing. */
2833char *owl_function_ztext_stylestrip(char *zt)
2834{
2835  owl_fmtext fm;
2836  char *plaintext;
2837
2838  owl_fmtext_init_null(&fm);
2839  owl_fmtext_append_ztext(&fm, zt);
2840  plaintext = owl_fmtext_print_plain(&fm);
2841  owl_fmtext_free(&fm);
2842  return(plaintext);
2843}
2844
2845/* Popup a buddylisting.  If file is NULL use the default .anyone */
2846void owl_function_buddylist(int aim, int zephyr, char *file)
2847{
2848  int i, j, idle;
2849  owl_fmtext fm;
2850  owl_buddylist *b;
2851  char *foo, *timestr;
2852#ifdef HAVE_LIBZEPHYR
2853  char *ourfile, *tmp, buff[LINE], *line;
2854  ZLocations_t location[200];
2855  FILE *f;
2856  int numlocs, ret;
2857#endif
2858
2859  owl_fmtext_init_null(&fm);
2860
2861  if (aim && owl_global_is_aimloggedin(&g)) {
2862    b=owl_global_get_buddylist(&g);
2863
2864    owl_fmtext_append_bold(&fm, "AIM users logged in:\n");
2865    j=owl_buddylist_get_size(b);
2866    for (i=0; i<j; i++) {
2867      idle=owl_buddylist_get_idletime(b, i);
2868      if (idle!=0) {
2869        timestr=owl_util_minutes_to_timestr(idle);
2870      } else {
2871        timestr=owl_strdup("");
2872      }
2873      foo=owl_sprintf("  %-15.15s %-12.12s\n",
2874                      owl_buddylist_get_buddy(b, i),
2875                      timestr);
2876      owl_fmtext_append_normal(&fm, foo);
2877      owl_free(timestr);
2878      owl_free(foo);
2879    }
2880  }
2881
2882#ifdef HAVE_LIBZEPHYR
2883  if (zephyr) {
2884    if (file==NULL) {
2885      tmp=owl_global_get_homedir(&g);
2886      if (!tmp) {
2887        owl_function_makemsg("Could not determine home directory");
2888        return;
2889      }
2890      ourfile=owl_malloc(strlen(tmp)+50);
2891      sprintf(ourfile, "%s/.anyone", owl_global_get_homedir(&g));
2892    } else {
2893      ourfile=owl_strdup(file);
2894    }
2895   
2896    f=fopen(ourfile, "r");
2897    if (!f) {
2898      owl_function_makemsg("Error opening file %s: %s",
2899                           ourfile,
2900                           strerror(errno) ? strerror(errno) : "");
2901      return;
2902    }
2903
2904    owl_fmtext_append_bold(&fm, "Zephyr users logged in:\n");
2905   
2906    while (fgets(buff, LINE, f)!=NULL) {
2907      /* ignore comments, blank lines etc. */
2908      if (buff[0]=='#') continue;
2909      if (buff[0]=='\n') continue;
2910      if (buff[0]=='\0') continue;
2911     
2912      /* strip the \n */
2913      buff[strlen(buff)-1]='\0';
2914     
2915      /* ingore from # on */
2916      tmp=strchr(buff, '#');
2917      if (tmp) tmp[0]='\0';
2918     
2919      /* ingore from SPC */
2920      tmp=strchr(buff, ' ');
2921      if (tmp) tmp[0]='\0';
2922     
2923      /* stick on the local realm. */
2924      if (!strchr(buff, '@')) {
2925        strcat(buff, "@");
2926        strcat(buff, ZGetRealm());
2927      }
2928     
2929      ret=ZLocateUser(buff, &numlocs, ZAUTH);
2930      if (ret!=ZERR_NONE) {
2931        owl_function_makemsg("Error getting location for %s", buff);
2932        continue;
2933      }
2934     
2935      numlocs=200;
2936      ret=ZGetLocations(location, &numlocs);
2937      if (ret==0) {
2938        for (i=0; i<numlocs; i++) {
2939          line=malloc(strlen(location[i].host)+strlen(location[i].time)+strlen(location[i].tty)+100);
2940          tmp=short_zuser(buff);
2941          sprintf(line, "  %-10.10s %-24.24s %-12.12s  %20.20s\n",
2942                  tmp,
2943                  location[i].host,
2944                  location[i].tty,
2945                  location[i].time);
2946          owl_fmtext_append_normal(&fm, line);
2947          owl_free(tmp);
2948        }
2949        if (numlocs>=200) {
2950          owl_fmtext_append_normal(&fm, "  Too many locations found for this user, truncating.\n");
2951        }
2952      }
2953    }
2954    fclose(f);
2955    owl_free(ourfile);
2956  }
2957#endif
2958 
2959  owl_function_popless_fmtext(&fm);
2960  owl_fmtext_free(&fm);
2961}
2962
2963void owl_function_dump(char *filename) 
2964{
2965  int i, j, count;
2966  owl_message *m;
2967  owl_view *v;
2968  FILE *file;
2969  /* struct stat sbuf; */
2970
2971  v=owl_global_get_current_view(&g);
2972
2973  /* in the future make it ask yes/no */
2974  /*
2975  ret=stat(filename, &sbuf);
2976  if (!ret) {
2977    ret=owl_function_askyesno("File exists, continue? [Y/n]");
2978    if (!ret) return;
2979  }
2980  */
2981
2982  file=fopen(filename, "w");
2983  if (!file) {
2984    owl_function_makemsg("Error opening file");
2985    return;
2986  }
2987
2988  count=0;
2989  j=owl_view_get_size(v);
2990  for (i=0; i<j; i++) {
2991    m=owl_view_get_element(v, i);
2992    fputs(owl_message_get_text(m), file);
2993  }
2994  fclose(file);
2995}
2996
2997
2998
2999void owl_function_do_newmsgproc(void)
3000{
3001  if (owl_global_get_newmsgproc(&g) && strcmp(owl_global_get_newmsgproc(&g), "")) {
3002    /* if there's a process out there, we need to check on it */
3003    if (owl_global_get_newmsgproc_pid(&g)) {
3004      owl_function_debugmsg("Checking on newmsgproc pid==%i", owl_global_get_newmsgproc_pid(&g));
3005      owl_function_debugmsg("Waitpid return is %i", waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG));
3006      waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG);
3007      if (waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG)==-1) {
3008        /* it exited */
3009        owl_global_set_newmsgproc_pid(&g, 0);
3010        owl_function_debugmsg("newmsgproc exited");
3011      } else {
3012        owl_function_debugmsg("newmsgproc did not exit");
3013      }
3014    }
3015   
3016    /* if it exited, fork & exec a new one */
3017    if (owl_global_get_newmsgproc_pid(&g)==0) {
3018      int i, myargc;
3019      i=fork();
3020      if (i) {
3021        /* parent set the child's pid */
3022        owl_global_set_newmsgproc_pid(&g, i);
3023        owl_function_debugmsg("I'm the parent and I started a new newmsgproc with pid %i", i);
3024      } else {
3025        /* child exec's the program */
3026        char **parsed;
3027        parsed=owl_parseline(owl_global_get_newmsgproc(&g), &myargc);
3028        if (myargc < 0) {
3029          owl_function_debugmsg("Could not parse newmsgproc '%s': unbalanced quotes?", owl_global_get_newmsgproc(&g));
3030        }
3031        if (myargc <= 0) {
3032          _exit(127);
3033        }
3034        parsed=realloc(parsed, sizeof(*parsed) * (myargc+1));
3035        parsed[myargc] = NULL;
3036       
3037        owl_function_debugmsg("About to exec \"%s\" with %d arguments", parsed[0], myargc);
3038       
3039        execvp(parsed[0], parsed);
3040       
3041       
3042        /* was there an error exec'ing? */
3043        owl_function_debugmsg("Cannot run newmsgproc '%s': cannot exec '%s': %s", 
3044                              owl_global_get_newmsgproc(&g), parsed[0], strerror(errno));
3045        _exit(127);
3046      }
3047    }
3048  }
3049}
3050
3051/* print the xterm escape sequence to raise the window */
3052void owl_function_xterm_raise(void)
3053{
3054  printf("\033[5t");
3055}
3056
3057/* print the xterm escape sequence to deiconify the window */
3058void owl_function_xterm_deiconify(void)
3059{
3060  printf("\033[1t");
3061}
3062
3063/* Add the specified command to the startup file.  Eventually this
3064 * should be clever, and rewriting settings that will obviosly
3065 * override earlier settings with 'set' 'bindkey' and 'alias'
3066 * commands.  For now though we just remove any line that would
3067 * duplicate this one and then append this line to the end of
3068 * startupfile.
3069 */
3070void owl_function_addstartup(char *buff)
3071{
3072  FILE *file;
3073  char *filename;
3074
3075  filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
3076  file=fopen(filename, "a");
3077  if (!file) {
3078    owl_function_makemsg("Error opening startupfile for new command");
3079    owl_free(filename);
3080    return;
3081  }
3082
3083  /* delete earlier copies */
3084  owl_util_file_deleteline(filename, buff, 1);
3085  owl_free(filename);
3086
3087  /* add this line */
3088  fprintf(file, "%s\n", buff);
3089
3090  fclose(file);
3091}
3092
3093/* Remove the specified command from the startup file. */
3094void owl_function_delstartup(char *buff)
3095{
3096  char *filename;
3097  filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
3098  owl_util_file_deleteline(filename, buff, 1);
3099  owl_free(filename);
3100}
3101
3102void owl_function_execstartup(void)
3103{
3104  FILE *file;
3105  char *filename;
3106  char buff[LINE];
3107
3108  filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
3109  file=fopen(filename, "r");
3110  owl_free(filename);
3111  if (!file) {
3112    /* just fail silently if it doesn't exist */
3113    return;
3114  }
3115  while (fgets(buff, LINE, file)!=NULL) {
3116    buff[strlen(buff)-1]='\0';
3117    owl_function_command(buff);
3118  }
3119  fclose(file);
3120}
3121
3122
3123void owl_function_change_style(owl_view *v, char *stylename)
3124{
3125  owl_style *s;
3126
3127  s=owl_global_get_style_by_name(&g, stylename);
3128  if (!s) {
3129    owl_function_makemsg("No style named %s", stylename);
3130    return;
3131  }
3132  owl_view_set_style(v, s);
3133  owl_messagelist_invalidate_formats(owl_global_get_msglist(&g));
3134  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
3135  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3136 
3137}
3138
3139void owl_function_toggleoneline()
3140{
3141  owl_view *v;
3142  owl_style *s;
3143
3144  v=owl_global_get_current_view(&g);
3145  s=owl_view_get_style(v);
3146
3147  if (!owl_style_matches_name(s, "oneline")) {
3148    owl_function_change_style(v, "oneline");
3149  } else {
3150    owl_function_change_style(v, owl_global_get_default_style(&g));
3151  }
3152
3153  owl_messagelist_invalidate_formats(owl_global_get_msglist(&g));
3154  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
3155  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3156}
Note: See TracBrowser for help on using the repository browser.