source: functions.c @ 7d4fbcd

barnowl_perlaimdebianowlrelease-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 7d4fbcd was 7d4fbcd, checked in by James M. Kretchmar <kretch@mit.edu>, 22 years ago
Initial check in
  • Property mode set to 100644
File size: 51.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 <com_err.h>
7#include <time.h>
8#include "owl.h"
9
10void owl_function_noop(void) {
11  return;
12}
13
14char *owl_function_command(char *cmdbuff) {
15  owl_function_debugmsg("executing command: %s", cmdbuff);
16  return owl_cmddict_execute(owl_global_get_cmddict(&g), 
17                             owl_global_get_context(&g), cmdbuff);
18}
19
20void owl_function_command_norv(char *cmdbuff) {
21  char *rv;
22  rv = owl_function_command(cmdbuff);
23  if (rv) owl_free(rv);
24}
25
26void owl_function_command_alias(char *alias_from, char *alias_to) {
27  owl_cmddict_add_alias(owl_global_get_cmddict(&g), alias_from, alias_to);
28}
29
30owl_cmd *owl_function_get_cmd(char *name) {
31  return owl_cmddict_find(owl_global_get_cmddict(&g), name);
32}
33
34void owl_function_show_commands() {
35  owl_list l;
36  owl_fmtext fm;
37
38  owl_fmtext_init_null(&fm);
39  owl_fmtext_append_bold(&fm, "Commands:  ");
40  owl_fmtext_append_normal(&fm, "(use 'show command <name>' for details)\n");
41  owl_cmddict_get_names(owl_global_get_cmddict(&g), &l);
42  owl_fmtext_append_list(&fm, &l, "\n", owl_function_cmd_describe);
43  owl_fmtext_append_normal(&fm, "\n");
44  owl_function_popless_fmtext(&fm);
45  owl_cmddict_namelist_free(&l);
46  owl_fmtext_free(&fm);
47}
48
49char *owl_function_cmd_describe(void *name) {
50  owl_cmd *cmd = owl_cmddict_find(owl_global_get_cmddict(&g), name);
51  if (cmd) return owl_cmd_describe(cmd);
52  else return(NULL);
53}
54
55void owl_function_show_command(char *name) {
56  owl_function_help_for_command(name);
57}
58
59void owl_function_adminmsg(char *header, char *body) {
60  owl_message *m;
61  int followlast;
62
63  followlast=owl_global_should_followlast(&g);
64  m=owl_malloc(sizeof(owl_message));
65  owl_message_create_admin(m, header, body);
66  owl_messagelist_append_element(owl_global_get_msglist(&g), m);
67  owl_view_consider_message(owl_global_get_current_view(&g), m);
68
69  if (followlast) owl_function_lastmsg_noredisplay();
70
71  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
72  if (owl_popwin_is_active(owl_global_get_popwin(&g))) {
73    owl_popwin_refresh(owl_global_get_popwin(&g));
74  }
75 
76  wnoutrefresh(owl_global_get_curs_recwin(&g));
77  owl_global_set_needrefresh(&g);
78}
79
80void owl_function_adminmsg_outgoing(char *header, char *body, char *zwriteline) {
81  owl_message *m;
82  int followlast;
83 
84  followlast=owl_global_should_followlast(&g);
85  m=owl_malloc(sizeof(owl_message));
86  owl_message_create_admin(m, header, body);
87  owl_message_set_admin_outgoing(m, zwriteline);
88  owl_messagelist_append_element(owl_global_get_msglist(&g), m);
89  owl_view_consider_message(owl_global_get_current_view(&g), m);
90
91  if (followlast) owl_function_lastmsg_noredisplay();
92
93  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
94  if (owl_popwin_is_active(owl_global_get_popwin(&g))) {
95    owl_popwin_refresh(owl_global_get_popwin(&g));
96  }
97 
98  wnoutrefresh(owl_global_get_curs_recwin(&g));
99  owl_global_set_needrefresh(&g);
100}
101
102void owl_function_zwrite_setup(char *line) {
103  owl_editwin *e;
104  char buff[1024];
105  owl_zwrite z;
106  int ret;
107
108  /* check the arguments */
109  ret=owl_zwrite_create_from_line(&z, line);
110  if (ret) {
111    owl_function_makemsg("Error in zwrite arugments");
112    owl_zwrite_free(&z);
113    return;
114  }
115
116  /* send a ping if necessary */
117  if (owl_global_is_txping(&g)) {
118    owl_zwrite_send_ping(&z);
119  }
120  owl_zwrite_free(&z);
121
122  /* create and setup the editwin */
123  e=owl_global_get_typwin(&g);
124  owl_editwin_new_style(e, OWL_EDITWIN_STYLE_MULTILINE);
125
126  if (!owl_global_is_lockout_ctrld(&g)) {
127    owl_function_makemsg("Type your zephyr below.  End with ^D or a dot on a line by itself.  ^C will quit.");
128  } else {
129    owl_function_makemsg("Type your zephyr below.  End with a dot on a line by itself.  ^C will quit.");
130  }
131
132  owl_editwin_clear(e);
133  owl_editwin_set_dotsend(e);
134  strcpy(buff, "----> ");
135  strcat(buff, line);
136  strcat(buff, "\n");
137  owl_editwin_set_locktext(e, buff);
138
139  /* make it active */
140  owl_global_set_typwin_active(&g);
141}
142
143void owl_function_zwrite(char *line) {
144  char *tmpbuff, buff[1024];
145  owl_zwrite z;
146  int i, j;
147
148  /* create the zwrite and send the message */
149  owl_zwrite_create_from_line(&z, line);
150  owl_zwrite_send_message(&z, owl_editwin_get_text(owl_global_get_typwin(&g)));
151  owl_function_makemsg("Waiting for ack...");
152
153  /* display the message as an admin message in the receive window */
154  if (owl_global_is_displayoutgoing(&g) && owl_zwrite_is_personal(&z)) {
155    tmpbuff=owl_malloc(strlen(owl_editwin_get_text(owl_global_get_typwin(&g)))+1024);
156    owl_zwrite_get_recipstr(&z, buff);
157    sprintf(tmpbuff, "Message sent to %s", buff);
158    owl_function_adminmsg_outgoing(tmpbuff, owl_editwin_get_text(owl_global_get_typwin(&g)), line);
159    owl_free(tmpbuff);
160  }
161
162  /* log it if we have logging turned on */
163  if (owl_global_is_logging(&g) && owl_zwrite_is_personal(&z)) {
164    j=owl_zwrite_get_numrecips(&z);
165    for (i=0; i<j; i++) {
166      owl_log_outgoing(owl_zwrite_get_recip_n(&z, i),
167                       owl_editwin_get_text(owl_global_get_typwin(&g)));
168    }
169  }
170
171  /* free the zwrite */
172  owl_zwrite_free(&z);
173}
174
175
176
177void owl_function_nextmsg() {
178  int curmsg;
179  owl_view *v;
180
181  v=owl_global_get_current_view(&g);
182 
183  curmsg=owl_global_get_curmsg(&g);
184  curmsg++;
185  if (curmsg>owl_view_get_size(v)-1) {
186    curmsg=owl_view_get_size(v)-1;
187    if (curmsg<0) curmsg=0;
188    owl_function_beep();
189    owl_function_makemsg("already at last message");
190  }
191  owl_global_set_curmsg(&g, curmsg);
192  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
193
194  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
195  owl_global_set_direction_downwards(&g);
196}
197
198
199void owl_function_prevmsg() {
200  int curmsg;
201 
202  curmsg=owl_global_get_curmsg(&g);
203  curmsg--;
204  if (curmsg<0) {
205    curmsg=0;
206    owl_function_beep();
207    owl_function_makemsg("already at first message");
208  }
209  owl_global_set_curmsg(&g, curmsg);
210  owl_function_calculate_topmsg(OWL_DIRECTION_UPWARDS);
211  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
212  owl_global_set_direction_upwards(&g);
213}
214
215
216void owl_function_nextmsg_notdeleted() {
217  int curmsg;
218  owl_message *m;
219  owl_view *v;
220
221  v=owl_global_get_current_view(&g);
222
223  curmsg=owl_global_get_curmsg(&g);
224  while (1) {
225    curmsg++;
226
227    /* if we're out of bounds get in bounds and stop */
228    if (curmsg>owl_view_get_size(v)-1) {
229      curmsg=owl_view_get_size(v)-1;
230      if (curmsg<0) curmsg=0;
231      owl_function_makemsg("already at last non-deleted message");
232      break;
233    }
234
235    /* if this one is not deleted we can stop where we are */
236    m=owl_view_get_element(v, curmsg);
237    if (!owl_message_is_delete(m)) {
238      break;
239    }
240  }
241 
242  owl_global_set_curmsg(&g, curmsg);
243  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
244  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
245  owl_global_set_direction_downwards(&g);
246}
247
248
249void owl_function_prevmsg_notdeleted() {
250  int curmsg;
251  owl_message *m;
252  owl_view *v;
253
254  v=owl_global_get_current_view(&g);
255
256  curmsg=owl_global_get_curmsg(&g);
257  while(1) {
258    curmsg--;
259
260    /* if we're out of bounds get in bounds and stop */
261    if (curmsg<0) {
262      curmsg=0;
263      owl_function_makemsg("already at first non-deleted message");
264      break;
265    }
266
267    /* if this one is not deleted we can stop where we are */
268    m=owl_view_get_element(v, curmsg);
269    if (!owl_message_is_delete(m)) {
270      break;
271    }
272  }
273
274  owl_global_set_curmsg(&g, curmsg);
275  owl_function_calculate_topmsg(OWL_DIRECTION_UPWARDS);
276  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
277  owl_global_set_direction_upwards(&g);
278}
279
280
281void owl_function_deletecur() {
282  int curmsg;
283  owl_view *v;
284
285  v=owl_global_get_current_view(&g);
286
287  /* bail if there's no current message */
288  if (owl_view_get_size(v) < 1) {
289    owl_function_makemsg("No current message to delete");
290    return;
291  }
292
293  /* mark the message for deletion */
294  curmsg=owl_global_get_curmsg(&g);
295  owl_view_delete_element(v, curmsg);
296
297  /* move the poiner in the appropriate direction to the next undeleted msg */
298  if (owl_global_get_direction(&g)==OWL_DIRECTION_UPWARDS) {
299    owl_command_prev_notdeleted();
300  } else {
301    owl_command_next_notdeleted();
302  }
303}
304
305
306void owl_function_undeletecur() {
307  int curmsg;
308  owl_view *v;
309
310  v=owl_global_get_current_view(&g);
311 
312  if (owl_view_get_size(v) < 1) {
313    owl_function_makemsg("No current message to undelete");
314    return;
315  }
316  curmsg=owl_global_get_curmsg(&g);
317
318  owl_view_undelete_element(v, curmsg);
319
320  if (owl_global_get_direction(&g)==OWL_DIRECTION_UPWARDS) {
321    if (curmsg>0) {
322      owl_command_prev();
323    } else {
324      owl_command_next();
325    }
326  } else {
327    owl_command_next();
328  }
329
330  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
331}
332
333
334void owl_function_expunge() {
335  int curmsg;
336  owl_message *m;
337  owl_messagelist *ml;
338  owl_view *v;
339  int i, j;
340
341  curmsg=owl_global_get_curmsg(&g);
342  v=owl_global_get_current_view(&g);
343  ml=owl_global_get_msglist(&g);
344
345  /* first try to move to an undeleted message in the view*/
346  m=owl_view_get_element(v, curmsg);
347  if (owl_message_is_delete(m)) {
348    /* try to find the next undeleted message */
349    j=owl_view_get_size(v);
350    for (i=curmsg; i<j; i++) {
351      if (!owl_message_is_delete(owl_view_get_element(v, i))) {
352        owl_global_set_curmsg(&g, i);
353        break;
354      }
355    }
356
357    /* if we weren't successful try to find one backwards */
358    curmsg=owl_global_get_curmsg(&g);
359    if (owl_message_is_delete(owl_view_get_element(v, curmsg))) {
360      for (i=curmsg; i>0; i--) {
361        if (!owl_message_is_delete(owl_view_get_element(v, i))) {
362          owl_global_set_curmsg(&g, i);
363          break;
364        }
365      }
366    }
367  }
368
369  /* expunge the message list */
370  owl_messagelist_expunge(ml);
371
372  /* update all views (we only have one right now) */
373  owl_view_recalculate(v);
374
375  if (curmsg>owl_view_get_size(v)-1) {
376    owl_global_set_curmsg(&g, owl_view_get_size(v)-1);
377    if (owl_global_get_curmsg(&g)<0) {
378      owl_global_set_curmsg(&g, 0);
379    }
380    owl_function_calculate_topmsg(OWL_DIRECTION_NONE);
381  }
382
383  /* if there are no messages set the direction to down in case we
384     delete everything upwards */
385  owl_global_set_direction_downwards(&g);
386 
387  owl_function_makemsg("Messages expunged");
388  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
389}
390
391
392void owl_function_firstmsg() {
393  owl_global_set_curmsg(&g, 0);
394  owl_global_set_topmsg(&g, 0);
395  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
396  owl_global_set_direction_downwards(&g);
397}
398
399void owl_function_lastmsg_noredisplay() {
400  int curmsg;
401  owl_view *v;
402
403  v=owl_global_get_current_view(&g);
404 
405  curmsg=owl_view_get_size(v)-1;
406  if (curmsg<0) curmsg=0;
407  owl_global_set_curmsg(&g, curmsg);
408  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
409  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
410  owl_global_set_direction_downwards(&g);
411}
412
413void owl_function_lastmsg() {
414  owl_function_lastmsg_noredisplay();
415  owl_mainwin_redisplay(owl_global_get_mainwin(&g)); 
416}
417
418void owl_function_shift_right() {
419  owl_global_set_rightshift(&g, owl_global_get_rightshift(&g)+10);
420  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
421  owl_global_set_needrefresh(&g);
422}
423
424
425void owl_function_shift_left() {
426  int shift;
427
428  shift=owl_global_get_rightshift(&g);
429  if (shift>=10) {
430    owl_global_set_rightshift(&g, shift-10);
431    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
432    owl_global_set_needrefresh(&g);
433  } else {
434    owl_function_beep();
435    owl_function_makemsg("Already full left");
436  }
437}
438
439
440void owl_function_unsuball() {
441  unsuball();
442  owl_function_makemsg("Unsubscribed from all messages.");
443}
444
445void owl_function_loadsubs(char *file) {
446  int ret;
447  ret=owl_zephyr_loadsubs(file);
448  if (ret==0) {
449    owl_function_makemsg("Subscribed to messages from file.");
450  } else if (ret==-1) {
451    owl_function_makemsg("Could not open file.");
452  } else {
453    owl_function_makemsg("Error subscribing to messages from file.");
454  }
455}
456
457void owl_function_suspend() {
458  endwin();
459  printf("\n");
460  kill(getpid(), SIGSTOP);
461
462  /* resize to reinitialize all the windows when we come back */
463  owl_command_resize();
464}
465
466void owl_function_zaway_toggle() {
467  if (!owl_global_is_zaway(&g)) {
468    owl_global_set_zaway_msg(&g, owl_global_get_zaway_msg_default(&g));
469    owl_function_zaway_on();
470  } else {
471    owl_function_zaway_off();
472  }
473}
474
475void owl_function_zaway_on() {
476  owl_global_set_zaway_on(&g);
477  owl_function_makemsg("zaway set (%s)", owl_global_get_zaway_msg(&g));
478}
479
480void owl_function_zaway_off() {
481  owl_global_set_zaway_off(&g);
482  owl_function_makemsg("zaway off");
483}
484
485void owl_function_quit() {
486  char *ret;
487 
488  /* zlog out if we need to */
489  if (owl_global_is_shutdownlogout(&g)) {
490    owl_function_zlog_out();
491  }
492
493  /* execute the commands in shutdown */
494  ret = owl_config_execute("owl::shutdown();");
495  if (ret) owl_free(ret);
496
497  /* final clean up */
498  unsuball();
499  ZClosePort();
500  endwin();
501  owl_function_debugmsg("Quitting Owl");
502  exit(0);
503}
504
505
506void owl_function_zlog_in() {
507  char *exposure, *eset;
508  int ret;
509
510  eset=EXPOSE_REALMVIS;
511  exposure=ZGetVariable("exposure");
512  if (exposure==NULL) {
513    eset=EXPOSE_REALMVIS;
514  } else if (!strcasecmp(exposure,EXPOSE_NONE)) {
515    eset = EXPOSE_NONE;
516  } else if (!strcasecmp(exposure,EXPOSE_OPSTAFF)) {
517    eset = EXPOSE_OPSTAFF;
518  } else if (!strcasecmp(exposure,EXPOSE_REALMVIS)) {
519    eset = EXPOSE_REALMVIS;
520  } else if (!strcasecmp(exposure,EXPOSE_REALMANN)) {
521    eset = EXPOSE_REALMANN;
522  } else if (!strcasecmp(exposure,EXPOSE_NETVIS)) {
523    eset = EXPOSE_NETVIS;
524  } else if (!strcasecmp(exposure,EXPOSE_NETANN)) {
525    eset = EXPOSE_NETANN;
526  }
527   
528  ret=ZSetLocation(eset);
529  if (ret != ZERR_NONE) {
530    /*
531      char buff[LINE];
532      sprintf(buff, "Error setting location: %s", error_message(ret));
533      owl_function_makemsg(buff);
534    */
535  }
536}
537
538void owl_function_zlog_out() {
539  int ret;
540 
541  ret=ZUnsetLocation();
542  if (ret != ZERR_NONE) {
543    /*
544      char buff[LINE];
545      sprintf(buff, "Error unsetting location: %s", error_message(ret));
546      owl_function_makemsg(buff);
547    */
548  }
549}
550
551
552void owl_function_makemsg(char *fmt, ...) {
553  va_list ap;
554  char buff[2048];
555
556  va_start(ap, fmt);
557  werase(owl_global_get_curs_msgwin(&g));
558 
559  vsnprintf(buff, 2048, fmt, ap);
560  owl_function_debugmsg("makemsg: %s", buff);
561  waddstr(owl_global_get_curs_msgwin(&g), buff); 
562  wnoutrefresh(owl_global_get_curs_msgwin(&g));
563  owl_global_set_needrefresh(&g);
564  va_end(ap);
565}
566
567void owl_function_errormsg(char *fmt, ...) {
568  va_list ap;
569  char buff[2048];
570
571  va_start(ap, fmt);
572  werase(owl_global_get_curs_msgwin(&g));
573 
574  vsnprintf(buff, 2048, fmt, ap);
575  owl_function_debugmsg("ERROR: %s", buff);
576  waddstr(owl_global_get_curs_msgwin(&g), buff); 
577  waddstr(owl_global_get_curs_msgwin(&g), "ERROR: "); 
578  wnoutrefresh(owl_global_get_curs_msgwin(&g));
579  owl_global_set_needrefresh(&g);
580  va_end(ap);
581}
582
583
584void owl_function_openurl() {
585  /* visit the first url in the current message */
586  owl_message *m;
587  owl_view *v;
588  char *ptr1, *ptr2, *text, url[LINE], tmpbuff[LINE];
589  int webbrowser;
590
591  webbrowser = owl_global_get_webbrowser(&g);
592
593  if (webbrowser < 0 || webbrowser == OWL_WEBBROWSER_NONE) {
594    owl_function_makemsg("No browser selected");
595    return;
596  }
597
598  v=owl_global_get_current_view(&g);
599 
600  if (owl_view_get_size(v)==0) {
601    owl_function_makemsg("No current message selected");
602    return;
603  }
604
605  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
606  text=owl_message_get_text(m);
607
608  /* First look for a good URL */ 
609  if ((ptr1=strstr(text, "http://"))!=NULL) {
610    ptr2=strpbrk(ptr1, " \n\t");
611    if (ptr2) {
612      strncpy(url, ptr1, ptr2-ptr1+1);
613      url[ptr2-ptr1+1]='\0';
614    } else {
615      strcpy(url, ptr1);
616    }
617
618    /* if we had <http strip a trailing > */
619    if (ptr1>text && ptr1[-1]=='<') {
620      if (url[strlen(url)-1]=='>') {
621        url[strlen(url)-1]='\0';
622      }
623    }
624  } else if ((ptr1=strstr(text, "https://"))!=NULL) {
625    /* Look for an https URL */ 
626    ptr2=strpbrk(ptr1, " \n\t");
627    if (ptr2) {
628      strncpy(url, ptr1, ptr2-ptr1+1);
629      url[ptr2-ptr1+1]='\0';
630    } else {
631      strcpy(url, ptr1);
632    }
633   
634    /* if we had <http strip a trailing > */
635    if (ptr1>text && ptr1[-1]=='<') {
636      if (url[strlen(url)-1]=='>') {
637        url[strlen(url)-1]='\0';
638      }
639    }
640  } else if ((ptr1=strstr(text, "www."))!=NULL) {
641    /* if we can't find a real url look for www.something */
642    ptr2=strpbrk(ptr1, " \n\t");
643    if (ptr2) {
644      strncpy(url, ptr1, ptr2-ptr1+1);
645      url[ptr2-ptr1+1]='\0';
646    } else {
647      strcpy(url, ptr1);
648    }
649  } else {
650    owl_function_beep();
651    owl_function_makemsg("Could not find URL to open.");
652    return;
653  }
654
655  /* Make sure there aren't any quotes or \'s in the url */
656  for (ptr1 = url; *ptr1; ptr1++) {
657    if (*ptr1 == '"' || *ptr1 == '\\') {
658      owl_function_beep();
659      owl_function_makemsg("URL contains invalid characters.");
660      return;
661    }
662  }
663 
664  /* NOTE: There are potentially serious security issues here... */
665
666  /* open the page */
667  owl_function_makemsg("Opening %s", url);
668  if (webbrowser == OWL_WEBBROWSER_NETSCAPE) {
669    snprintf(tmpbuff, LINE, "netscape -remote \"openURL(%s)\" > /dev/null 2> /dev/null", url);
670    system(tmpbuff); 
671  } else if (webbrowser == OWL_WEBBROWSER_GALEON) {
672    snprintf(tmpbuff, LINE, "galeon \"%s\" > /dev/null 2> /dev/null &", url);
673    system(tmpbuff); 
674  }
675}
676
677void owl_function_calculate_topmsg(int direction) {
678  int recwinlines, y, savey, i, j, topmsg, curmsg, foo;
679  owl_mainwin *mw;
680  owl_view *v;
681
682  mw=owl_global_get_mainwin(&g);
683
684  topmsg=owl_global_get_topmsg(&g);
685  curmsg=owl_global_get_curmsg(&g);
686  v=owl_global_get_current_view(&g);
687  recwinlines=owl_global_get_recwin_lines(&g);
688
689  if (owl_view_get_size(v) < 1) {
690    return;
691  }
692 
693  /* Find number of lines from top to bottom of curmsg (store in savey) */
694  savey=0;
695  for (i=topmsg; i<=curmsg; i++) {
696    savey+=owl_message_get_numlines(owl_view_get_element(v, i));
697  }
698
699  /* If the direction is DOWNWARDS but we're off the bottom of the
700   *  screen, then set the topmsg to curmsg and scroll UPWARDS
701   */
702  if (direction == OWL_DIRECTION_DOWNWARDS) {
703    if (savey > recwinlines) {
704      topmsg=curmsg;
705      savey=owl_message_get_numlines(owl_view_get_element(v, i));
706      direction=OWL_DIRECTION_UPWARDS;
707    }
708  }
709
710  /* If our bottom line is less than 1/4 down the screen then scroll up */
711  if (direction == OWL_DIRECTION_UPWARDS || direction == OWL_DIRECTION_NONE) {
712    if (savey < (recwinlines / 4)) {
713      y=0;
714      for (j=curmsg; j>=0; j--) {
715        foo=owl_message_get_numlines(owl_view_get_element(v, j));
716        /* will we run the curmsg off the screen? */
717        if ((foo+y) >= recwinlines) {
718          j++;
719          if (j>curmsg) j=curmsg;
720          break;
721        }
722        /* have saved 1/2 the screen space? */
723        y+=foo;
724        if (y > (recwinlines / 2)) break;
725      }
726      if (j<0) j=0;
727      owl_global_set_topmsg(&g, j);
728      return;
729    }
730  }
731
732  if (direction == OWL_DIRECTION_DOWNWARDS || direction == OWL_DIRECTION_NONE) {
733    /* If curmsg bottom line is more than 3/4 down the screen then scroll down */
734    if (savey > ((recwinlines * 3)/4)) {
735      y=0;
736      /* count lines from the top until we can save 1/2 the screen size */
737      for (j=topmsg; j<curmsg; j++) {
738        y+=owl_message_get_numlines(owl_view_get_element(v, j));
739        if (y > (recwinlines / 2)) break;
740      }
741      if (j==curmsg) {
742        j--;
743      }
744      owl_global_set_topmsg(&g, j+1);
745      return;
746    }
747  }
748}
749
750
751void owl_function_resize() {
752  owl_global_set_resize_pending(&g);
753}
754
755
756void owl_function_run_buffercommand() {
757  char *buff;
758
759  buff=owl_global_get_buffercommand(&g);
760  if (!strncmp(buff, "zwrite ", 7)) {
761
762    owl_function_zwrite(buff);
763  }
764}
765
766void owl_function_debugmsg(char *fmt, ...) {
767  FILE *file;
768  time_t now;
769  char buff1[LINE], buff2[LINE];
770  va_list ap;
771  va_start(ap, fmt);
772
773  if (!owl_global_is_debug_fast(&g)) return;
774
775  file=fopen(owl_global_get_debug_file(&g), "a");
776  if (!file) return;
777
778  now=time(NULL);
779  strcpy(buff1, ctime(&now));
780  buff1[strlen(buff1)-1]='\0';
781
782  owl_global_get_runtime_string(&g, buff2);
783 
784  fprintf(file, "[%i -  %s - %s]: ", (int) getpid(), buff1, buff2);
785  vfprintf(file, fmt, ap);
786  fprintf(file, "\n");
787  fclose(file);
788
789  va_end(ap);
790}
791
792
793void owl_function_refresh() {
794  owl_function_resize();
795}
796
797void owl_function_beep() {
798  if (owl_global_is_bell(&g)) {
799    beep();
800  }
801}
802
803
804void owl_function_subscribe(char *class, char *inst, char *recip) {
805  int ret;
806
807  ret=owl_zephyr_sub(class, inst, recip);
808  if (ret) {
809    owl_function_makemsg("Error subscribing.");
810  } else {
811    owl_function_makemsg("Subscribed.");
812  }
813}
814
815
816void owl_function_unsubscribe(char *class, char *inst, char *recip) {
817  int ret;
818
819  ret=owl_zephyr_unsub(class, inst, recip);
820  if (ret) {
821    owl_function_makemsg("Error subscribing.");
822  } else {
823    owl_function_makemsg("Unsubscribed.");
824  }
825}
826
827
828void owl_function_set_cursor(WINDOW *win) {
829  wnoutrefresh(win);
830}
831
832
833void owl_function_full_redisplay() {
834  redrawwin(owl_global_get_curs_recwin(&g));
835  redrawwin(owl_global_get_curs_sepwin(&g));
836  redrawwin(owl_global_get_curs_typwin(&g));
837  redrawwin(owl_global_get_curs_msgwin(&g));
838
839  wnoutrefresh(owl_global_get_curs_recwin(&g));
840  wnoutrefresh(owl_global_get_curs_sepwin(&g));
841  wnoutrefresh(owl_global_get_curs_typwin(&g));
842  wnoutrefresh(owl_global_get_curs_msgwin(&g));
843 
844  sepbar("");
845  owl_function_makemsg("");
846
847  owl_global_set_needrefresh(&g);
848}
849
850
851void owl_function_popless_text(char *text) {
852  owl_popwin *pw;
853  owl_viewwin *v;
854
855  pw=owl_global_get_popwin(&g);
856  v=owl_global_get_viewwin(&g);
857
858  owl_popwin_up(pw);
859  owl_viewwin_init_text(v, owl_popwin_get_curswin(pw),
860                        owl_popwin_get_lines(pw), owl_popwin_get_cols(pw),
861                        text);
862  owl_popwin_refresh(pw);
863  owl_viewwin_redisplay(v, 0);
864  owl_global_set_needrefresh(&g);
865}
866
867
868void owl_function_popless_fmtext(owl_fmtext *fm) {
869  owl_popwin *pw;
870  owl_viewwin *v;
871
872  pw=owl_global_get_popwin(&g);
873  v=owl_global_get_viewwin(&g);
874
875  owl_popwin_up(pw);
876  owl_viewwin_init_fmtext(v, owl_popwin_get_curswin(pw),
877                   owl_popwin_get_lines(pw), owl_popwin_get_cols(pw),
878                   fm);
879  owl_popwin_refresh(pw);
880  owl_viewwin_redisplay(v, 0);
881  owl_global_set_needrefresh(&g);
882}
883
884void owl_function_about() {
885  char buff[5000];
886
887  sprintf(buff, "This is owl version %s\n", OWL_VERSION_STRING);
888  strcat(buff, "\nOwl was written by James Kretchmar at the Massachusetts\n");
889  strcat(buff, "Institute of Technology.  The first version, 0.5, was\n");
890  strcat(buff, "released in March 2002\n");
891  strcat(buff, "\n");
892  strcat(buff, "The name 'owl' was chosen in reference to the owls in the\n");
893  strcat(buff, "Harry Potter novels, who are tasked with carrying messages\n");
894  strcat(buff, "between Witches and Wizards.\n");
895  strcat(buff, "\n");
896  strcat(buff, "Copyright 2002 Massachusetts Institute of Technology\n");
897  strcat(buff, "\n");
898  strcat(buff, "Permission to use, copy, modify, and distribute this\n");
899  strcat(buff, "software and its documentation for any purpose and without\n");
900  strcat(buff, "fee is hereby granted, provided that the above copyright\n");
901  strcat(buff, "notice and this permission notice appear in all copies\n");
902  strcat(buff, "and in supporting documentation.  No representation is\n");
903  strcat(buff, "made about the suitability of this software for any\n");
904  strcat(buff, "purpose.  It is provided \"as is\" without express\n");
905  strcat(buff, "or implied warranty.\n");
906  owl_function_popless_text(buff);
907}
908
909void owl_function_info() {
910  owl_message *m;
911  ZNotice_t *n;
912  char buff[2048], tmpbuff[1024];
913  char *ptr;
914  int i, j, fields, len;
915  owl_view *v;
916
917  v=owl_global_get_current_view(&g);
918 
919  if (owl_view_get_size(v)==0) {
920    owl_function_makemsg("No message selected\n");
921    return;
922  }
923
924  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
925  if (!owl_message_is_zephyr(m)) {
926    sprintf(buff,   "Owl Message Id: %i\n", owl_message_get_id(m));
927    sprintf(buff, "%sTime          : %s\n", buff, owl_message_get_timestr(m));
928    owl_function_popless_text(buff);
929    return;
930  }
931
932  n=owl_message_get_notice(m);
933
934  sprintf(buff,   "Owl Msg ID: %i\n", owl_message_get_id(m));
935  sprintf(buff, "%sClass     : %s\n", buff, n->z_class);
936  sprintf(buff, "%sInstance  : %s\n", buff, n->z_class_inst);
937  sprintf(buff, "%sSender    : %s\n", buff, n->z_sender);
938  sprintf(buff, "%sRecip     : %s\n", buff, n->z_recipient);
939  sprintf(buff, "%sOpcode    : %s\n", buff, n->z_opcode);
940  strcat(buff,    "Kind      : ");
941  if (n->z_kind==UNSAFE) {
942    strcat(buff, "UNSAFE\n");
943  } else if (n->z_kind==UNACKED) {
944    strcat(buff, "UNACKED\n");
945  } else if (n->z_kind==ACKED) {
946    strcat(buff, "ACKED\n");
947  } else if (n->z_kind==HMACK) {
948    strcat(buff, "HMACK\n");
949  } else if (n->z_kind==HMCTL) {
950    strcat(buff, "HMCTL\n");
951  } else if (n->z_kind==SERVACK) {
952    strcat(buff, "SERVACK\n");
953  } else if (n->z_kind==SERVNAK) {
954    strcat(buff, "SERVNAK\n");
955  } else if (n->z_kind==CLIENTACK) {
956    strcat(buff, "CLIENTACK\n");
957  } else if (n->z_kind==STAT) {
958    strcat(buff, "STAT\n");
959  } else {
960    strcat(buff, "ILLEGAL VALUE\n");
961  }
962  sprintf(buff, "%sTime      : %s\n", buff, owl_message_get_timestr(m));
963  sprintf(buff, "%sHost      : %s\n", buff, owl_message_get_hostname(m));
964  sprintf(buff, "%sPort      : %i\n", buff, n->z_port);
965  strcat(buff,    "Auth      : ");
966  if (n->z_auth == ZAUTH_FAILED) {
967    strcat(buff, "FAILED\n");
968  } else if (n->z_auth == ZAUTH_NO) {
969    strcat(buff, "NO\n");
970  } else if (n->z_auth == ZAUTH_YES) {
971    strcat(buff, "YES\n");
972  } else {
973    sprintf(buff, "%sUnknown State (%i)\n", buff, n->z_auth);
974  }
975  sprintf(buff, "%sCheckd Ath: %i\n", buff, n->z_checked_auth);
976  sprintf(buff, "%sMulti notc: %s\n", buff, n->z_multinotice);
977  sprintf(buff, "%sNum other : %i\n", buff, n->z_num_other_fields);
978  sprintf(buff, "%sMsg Len   : %i\n", buff, n->z_message_len);
979
980  sprintf(buff, "%sFields    : %i\n", buff, owl_zephyr_get_num_fields(n));
981
982  fields=owl_zephyr_get_num_fields(n);
983  for (i=0; i<fields; i++) {
984    sprintf(buff, "%sField %i   : ", buff, i+1);
985
986    ptr=owl_zephyr_get_field(n, i+1, &len);
987    if (!ptr) break;
988    if (len<30) {
989      strncpy(tmpbuff, ptr, len);
990      tmpbuff[len]='\0';
991    } else {
992      strncpy(tmpbuff, ptr, 30);
993      tmpbuff[30]='\0';
994      strcat(tmpbuff, "...");
995    }
996
997    /* just for testing for now */
998    for (j=0; j<strlen(tmpbuff); j++) {
999      if (tmpbuff[j]=='\n') tmpbuff[j]='~';
1000      if (tmpbuff[j]=='\r') tmpbuff[j]='!';
1001    }
1002
1003    strcat(buff, tmpbuff);
1004    strcat(buff, "\n");
1005  }
1006  sprintf(buff, "%sDefault Fm: %s\n", buff, n->z_default_format);
1007       
1008  owl_function_popless_text(buff);
1009}
1010
1011
1012void owl_function_curmsg_to_popwin() {
1013  owl_popwin *pw;
1014  owl_view *v;
1015  owl_message *m;
1016
1017  v = owl_global_get_current_view(&g);
1018
1019  pw=owl_global_get_popwin(&g);
1020
1021  if (owl_view_get_size(v)==0) {
1022    owl_function_makemsg("No current message");
1023    return;
1024  }
1025
1026  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
1027  owl_function_popless_fmtext(owl_message_get_fmtext(m));
1028}
1029
1030
1031void owl_function_page_curmsg(int step) {
1032  /* scroll down or up within the current message IF the message is truncated */
1033
1034  int offset, curmsg, lines;
1035  owl_view *v;
1036  owl_message *m;
1037
1038  offset=owl_global_get_curmsg_vert_offset(&g);
1039  v=owl_global_get_current_view(&g);
1040  if (owl_view_get_size(v)==0) return;
1041  curmsg=owl_global_get_curmsg(&g);
1042  m=owl_view_get_element(v, curmsg);
1043  lines=owl_message_get_numlines(m);
1044
1045  if (offset==0) {
1046    /* Bail if the curmsg isn't the last one displayed */
1047    if (curmsg != owl_mainwin_get_last_msg(owl_global_get_mainwin(&g))) {
1048      owl_function_makemsg("The entire message is already displayed");
1049      return;
1050    }
1051   
1052    /* Bail if we're not truncated */
1053    if (!owl_mainwin_is_curmsg_truncated(owl_global_get_mainwin(&g))) {
1054      owl_function_makemsg("The entire message is already displayed");
1055      return;
1056    }
1057  }
1058 
1059 
1060  /* don't scroll past the last line */
1061  if (step>0) {
1062    if (offset+step > lines-1) {
1063      owl_global_set_curmsg_vert_offset(&g, lines-1);
1064    } else {
1065      owl_global_set_curmsg_vert_offset(&g, offset+step);
1066    }
1067  }
1068
1069  /* would we be before the beginning of the message? */
1070  if (step<0) {
1071    if (offset+step<0) {
1072      owl_global_set_curmsg_vert_offset(&g, 0);
1073    } else {
1074      owl_global_set_curmsg_vert_offset(&g, offset+step);
1075    }
1076  }
1077 
1078  /* redisplay */
1079  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1080  owl_global_set_needrefresh(&g);
1081}
1082
1083void owl_function_resize_typwin(int newsize) {
1084  owl_global_set_typwin_lines(&g, newsize);
1085  owl_function_resize();
1086}
1087
1088void owl_function_typwin_grow() {
1089  int i;
1090
1091  i=owl_global_get_typwin_lines(&g);
1092  owl_function_resize_typwin(i+1);
1093}
1094
1095void owl_function_typwin_shrink() {
1096  int i;
1097
1098  i=owl_global_get_typwin_lines(&g);
1099  if (i>2) {
1100    owl_function_resize_typwin(i-1);
1101  }
1102}
1103
1104void owl_function_mainwin_pagedown() {
1105  int i;
1106
1107  i=owl_mainwin_get_last_msg(owl_global_get_mainwin(&g));
1108  if (i<0) return;
1109
1110  owl_global_set_curmsg(&g, i);
1111  owl_function_nextmsg();
1112}
1113
1114void owl_function_mainwin_pageup() {
1115  owl_global_set_curmsg(&g, owl_global_get_topmsg(&g));
1116  owl_function_prevmsg();
1117}
1118
1119void owl_function_getsubs() {
1120  int ret, num, i, one;
1121  ZSubscription_t sub;
1122  char *buff;
1123
1124  one = 1;
1125
1126  ret=ZRetrieveSubscriptions(0, &num);
1127  if (ret == ZERR_TOOMANYSUBS) {
1128
1129  }
1130
1131  buff=malloc(num*200);
1132  strcpy(buff, "");
1133  for (i=0; i<num; i++) {
1134    if ((ret = ZGetSubscriptions(&sub, &one)) != ZERR_NONE) {
1135      /* deal with error */
1136    } else {
1137      sprintf(buff, "%s<%s,%s,%s>\n", buff, sub.zsub_class, sub.zsub_classinst, sub.zsub_recipient);
1138    }
1139  }
1140
1141  owl_function_popless_text(buff);
1142  free(buff);
1143  ZFlushSubscriptions();
1144}
1145
1146#define PABUFLEN 5000
1147void owl_function_printallvars() {
1148  char buff[PABUFLEN], *pos, *name;
1149  owl_list varnames;
1150  int i, numvarnames, rem;
1151
1152  pos = buff;
1153  pos += sprintf(pos, "%-20s = %s\n", "VARIABLE", "VALUE");
1154  pos += sprintf(pos, "%-20s   %s\n",  "--------", "-----");
1155  owl_variable_dict_get_names(owl_global_get_vardict(&g), &varnames);
1156  rem = (buff+PABUFLEN)-pos-1;
1157  numvarnames = owl_list_get_size(&varnames);
1158  for (i=0; i<numvarnames; i++) {
1159    name = owl_list_get_element(&varnames, i);
1160    if (name && name[0]!='_') {
1161      rem = (buff+PABUFLEN)-pos-1;   
1162      pos += snprintf(pos, rem, "\n%-20s = ", name);
1163      rem = (buff+PABUFLEN)-pos-1;   
1164      owl_variable_get_tostring(owl_global_get_vardict(&g), name, pos, rem);
1165      pos = buff+strlen(buff);
1166    }
1167  }
1168  rem = (buff+PABUFLEN)-pos-1;   
1169  snprintf(pos, rem, "\n");
1170  owl_variable_dict_namelist_free(&varnames);
1171 
1172  owl_function_popless_text(buff);
1173}
1174
1175void owl_function_show_variables() {
1176  owl_list varnames;
1177  owl_fmtext fm; 
1178  int i, numvarnames;
1179  char *varname;
1180
1181  owl_fmtext_init_null(&fm);
1182  owl_fmtext_append_bold(&fm, 
1183      "Variables: (use 'show variable <name>' for details)\n");
1184  owl_variable_dict_get_names(owl_global_get_vardict(&g), &varnames);
1185  owl_variable_get_summaryheader(&fm);
1186  numvarnames = owl_list_get_size(&varnames);
1187  for (i=0; i<numvarnames; i++) {
1188    varname = owl_list_get_element(&varnames, i);
1189    if (varname && varname[0]!='_') {
1190      owl_variable_get_summary(owl_global_get_vardict(&g), varname, &fm);
1191    }
1192  }
1193  owl_variable_dict_namelist_free(&varnames);
1194  owl_function_popless_fmtext(&fm);
1195  owl_fmtext_free(&fm);
1196}
1197
1198void owl_function_show_variable(char *name) {
1199  owl_fmtext fm; 
1200
1201  owl_fmtext_init_null(&fm);
1202  owl_variable_get_help(owl_global_get_vardict(&g), name, &fm);
1203  owl_function_popless_fmtext(&fm);
1204  owl_fmtext_free(&fm); 
1205}
1206
1207/* note: this applies to global message list, not to view.
1208 * If flag is 1, deletes.  If flag is 0, undeletes. */
1209void owl_function_delete_by_id(int id, int flag) {
1210  owl_messagelist *ml;
1211  owl_message *m;
1212  ml = owl_global_get_msglist(&g);
1213  m = owl_messagelist_get_by_id(ml, id);
1214  if (m) {
1215    if (flag == 1) {
1216      owl_message_mark_delete(m);
1217    } else if (flag == 0) {
1218      owl_message_unmark_delete(m);
1219    }
1220    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1221    owl_global_set_needrefresh(&g);
1222  } else {
1223    owl_function_makemsg("No message with id %d: unable to mark for (un)delete",id);
1224  }
1225}
1226
1227void owl_function_delete_automsgs() {
1228  /* mark for deletion all messages in the current view that match the
1229   * 'trash' filter */
1230
1231  int i, j, count;
1232  owl_message *m;
1233  owl_view *v;
1234  owl_filter *f;
1235  char buff[LINE];
1236
1237  /* get the trash filter */
1238  f=owl_global_get_filter(&g, "trash");
1239  if (!f) {
1240    owl_function_makemsg("No trash filter defined");
1241    return;
1242  }
1243
1244  v=owl_global_get_current_view(&g);
1245
1246  count=0;
1247  j=owl_view_get_size(v);
1248  for (i=0; i<j; i++) {
1249    m=owl_view_get_element(v, i);
1250    if (owl_filter_message_match(f, m)) {
1251      count++;
1252      owl_message_mark_delete(m);
1253    }
1254  }
1255  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1256  sprintf(buff, "%i messages marked for deletion", count);
1257  owl_function_makemsg(buff);
1258  owl_global_set_needrefresh(&g);
1259}
1260
1261void owl_function_next_personal() {
1262  int i, j, curmsg, found;
1263  owl_view *v;
1264
1265  v=owl_global_get_current_view(&g);
1266  j=owl_view_get_size(v);
1267  curmsg=owl_global_get_curmsg(&g);
1268  found=0;
1269  for (i=curmsg+1; i<j; i++) {
1270    if (owl_message_is_personal(owl_view_get_element(v, i))) {
1271      owl_global_set_curmsg(&g, i);
1272      owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
1273      owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1274      owl_global_set_direction_downwards(&g);
1275      found=1;
1276      break;
1277    }
1278  }
1279  if (!found) {
1280    owl_function_makemsg("No next personal message found");
1281  }
1282}
1283
1284void owl_function_prev_personal() {
1285  int i, curmsg, found;
1286  owl_view *v;
1287
1288  v=owl_global_get_current_view(&g);
1289  curmsg=owl_global_get_curmsg(&g);
1290  found=0;
1291  for (i=curmsg-1; i>=0; i--) {
1292    if (owl_message_is_personal(owl_view_get_element(v, i))) {
1293      owl_global_set_curmsg(&g, i);
1294      owl_function_calculate_topmsg(OWL_DIRECTION_UPWARDS);
1295      owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1296      owl_global_set_direction_upwards(&g);
1297      found=1;
1298      break;
1299    }
1300  }
1301  if (!found) {
1302    owl_function_makemsg("No previous personal message found");
1303  }
1304}
1305
1306
1307void owl_function_status() {
1308  char buff[5000];
1309  time_t start;
1310  int up, days, hours, minutes;
1311
1312  start=owl_global_get_starttime(&g);
1313
1314  sprintf(buff, "Version: %s\n", OWL_VERSION_STRING);
1315  sprintf(buff, "%sScreen size: %i lines, %i columns\n", buff, owl_global_get_lines(&g), owl_global_get_cols(&g));
1316  sprintf(buff, "%sStartup Arugments: %s\n", buff, owl_global_get_startupargs(&g));
1317  sprintf(buff, "%sStartup Time: %s", buff, ctime(&start));
1318
1319  up=owl_global_get_runtime(&g);
1320  days=up/86400;
1321  up-=days*86400;
1322  hours=up/3600;
1323  up-=hours*3600;
1324  minutes=up/60;
1325  up-=minutes*60;
1326  sprintf(buff, "%sRun Time: %i days %2.2i:%2.2i:%2.2i\n", buff, days, hours, minutes, up);
1327
1328  if (owl_global_get_hascolors(&g)) {
1329    sprintf(buff, "%sColor: Yes, %i color pairs.\n", buff, owl_global_get_colorpairs(&g));
1330  } else {
1331    strcat(buff, "Color: No.\n");
1332  }
1333 
1334  owl_function_popless_text(buff);
1335}
1336
1337void owl_function_show_term() {
1338  owl_fmtext fm;
1339  char buff[LINE];
1340
1341  owl_fmtext_init_null(&fm);
1342  sprintf(buff, "Terminal Lines: %i\nTerminal Columns: %i\n",
1343          owl_global_get_lines(&g),
1344          owl_global_get_cols(&g));
1345  owl_fmtext_append_normal(&fm, buff);
1346
1347  if (owl_global_get_hascolors(&g)) {
1348    owl_fmtext_append_normal(&fm, "Color: Yes\n");
1349    sprintf(buff, "Number of color pairs: %i\n", owl_global_get_colorpairs(&g));
1350    owl_fmtext_append_normal(&fm, buff);
1351    sprintf(buff, "Can change colors: %s\n", can_change_color() ? "yes" : "no");
1352    owl_fmtext_append_normal(&fm, buff);
1353  } else {
1354    owl_fmtext_append_normal(&fm, "Color: No\n");
1355  }
1356
1357  owl_function_popless_fmtext(&fm);
1358  owl_fmtext_free(&fm);
1359}
1360
1361
1362void owl_function_reply(int type, int enter) {
1363  /* if type = 0 then normal reply.
1364   * if type = 1 then it's a reply to sender
1365   * if enter = 0 then allow the command to be edited
1366   * if enter = 1 then don't wait for editing
1367   */
1368  char buff[1024];
1369  owl_message *m;
1370  owl_filter *f;
1371 
1372  if (owl_view_get_size(owl_global_get_current_view(&g))==0) {
1373    owl_function_makemsg("No message selected");
1374  } else {
1375    char *class, *inst, *to;
1376   
1377    m=owl_view_get_element(owl_global_get_current_view(&g), owl_global_get_curmsg(&g));
1378
1379    /* first check if we catch the reply-lockout filter */
1380    f=owl_global_get_filter(&g, "reply-lockout");
1381    if (f) {
1382      if (owl_filter_message_match(f, m)) {
1383        owl_function_makemsg("Sorry, replies to this message have been disabled by the reply-lockout filter");
1384        return;
1385      }
1386    }
1387   
1388    if (owl_message_is_admin(m)) {
1389      if (owl_message_get_admintype(m)==OWL_MESSAGE_ADMINTYPE_OUTGOING) {
1390        owl_function_zwrite_setup(owl_message_get_zwriteline(m));
1391        owl_global_set_buffercommand(&g, owl_message_get_zwriteline(m));
1392      } else {
1393        owl_function_makemsg("You cannot reply to this admin message");
1394      }
1395    } else {
1396      if (owl_message_is_login(m)) {
1397        class="MESSAGE";
1398        inst="PERSONAL";
1399        to=owl_message_get_sender(m);
1400      } else if (type==1) {
1401        class="MESSAGE";
1402        inst="PERSONAL";
1403        to=owl_message_get_sender(m);
1404      } else {
1405        class=owl_message_get_class(m);
1406        inst=owl_message_get_instance(m);
1407        to=owl_message_get_recipient(m);
1408        if (!strcmp(to, "") || !strcmp(to, "*")) {
1409          to="";
1410        } else if (to[0]=='@') {
1411          /* leave it, to get the realm */
1412        } else {
1413          to=owl_message_get_sender(m);
1414        }
1415      }
1416     
1417      /* create the command line */
1418      strcpy(buff, "zwrite");
1419      if (strcasecmp(class, "message")) {
1420        sprintf(buff, "%s -c %s%s%s", buff, owl_getquoting(class), class, owl_getquoting(class));
1421      }
1422      if (strcasecmp(inst, "personal")) {
1423        sprintf(buff, "%s -i %s%s%s", buff, owl_getquoting(inst), inst, owl_getquoting(inst));
1424      }
1425      if (*to != '\0') {
1426        char *tmp;
1427        tmp=pretty_sender(to);
1428        sprintf(buff, "%s %s", buff, tmp);
1429        owl_free(tmp);
1430      }
1431
1432      if (enter) {
1433        owl_history_store(owl_global_get_history(&g), buff);
1434        owl_function_zwrite_setup(buff);
1435        owl_global_set_buffercommand(&g, buff);
1436      } else {
1437        owl_function_start_command(buff);
1438      }
1439    }
1440  }
1441}
1442
1443void owl_function_zlocate(char *user, int auth) {
1444  char buff[LINE], myuser[LINE];
1445  char *ptr;
1446
1447  strcpy(myuser, user);
1448  ptr=strchr(myuser, '@');
1449  if (!ptr) {
1450    strcat(myuser, "@");
1451    strcat(myuser, ZGetRealm());
1452  }
1453
1454  owl_zephyr_zlocate(myuser, buff, auth);
1455  owl_function_popless_text(buff);
1456}
1457
1458void owl_function_start_command(char *line) {
1459  int i, j;
1460  owl_editwin *tw;
1461
1462  tw=owl_global_get_typwin(&g);
1463  owl_global_set_typwin_active(&g);
1464  owl_editwin_set_locktext(tw, "command: ");
1465  owl_global_set_needrefresh(&g);
1466
1467  j=strlen(line);
1468  for (i=0; i<j; i++) {
1469    owl_editwin_process_char(tw, line[i]);
1470  }
1471  owl_editwin_redisplay(tw, 0);
1472}
1473
1474char *owl_function_exec(int argc, char **argv, char *buff, int type) {
1475  /* if type == 1 display in a popup
1476   * if type == 2 display an admin messages
1477   * if type == 0 return output
1478   * else display in a popup
1479   */
1480  char *newbuff, *redirect = " 2>&1 < /dev/null";
1481  char *out, buff2[1024];
1482  int size;
1483  FILE *p;
1484
1485  if (argc<2) {
1486    owl_function_makemsg("Wrong number of arguments to the pexec command");
1487    return NULL;
1488  }
1489
1490  buff = skiptokens(buff, 1);
1491  newbuff = owl_malloc(strlen(buff)+strlen(redirect)+1);
1492  strcpy(newbuff, buff);
1493  strcat(newbuff, redirect);
1494
1495  p=popen(newbuff, "r");
1496  out=owl_malloc(1024);
1497  size=1024;
1498  strcpy(out, "");
1499  while (fgets(buff2, 1024, p)!=NULL) {
1500    size+=1024;
1501    out=owl_realloc(out, size);
1502    strcat(out, buff2);
1503  }
1504  pclose(p);
1505
1506  if (type==1) {
1507    owl_function_popless_text(out);
1508  } else if (type==0) {
1509    return out;
1510  } else if (type==2) {
1511    owl_function_adminmsg(buff, out);
1512  } else {
1513    owl_function_popless_text(out);
1514  }
1515  owl_free(out);
1516  return NULL;
1517}
1518
1519
1520char *owl_function_perl(int argc, char **argv, char *buff, int type) {
1521  /* if type == 1 display in a popup
1522   * if type == 2 display an admin messages
1523   * if type == 0 return output
1524   * else display in a popup
1525   */
1526  char *perlout;
1527
1528  if (argc<2) {
1529    owl_function_makemsg("Wrong number of arguments to perl command");
1530    return NULL;
1531  }
1532
1533  /* consume first token (argv[0]) */
1534  buff = skiptokens(buff, 1);
1535
1536  perlout = owl_config_execute(buff);
1537  if (perlout) { 
1538    if (type==1) {
1539      owl_function_popless_text(perlout);
1540    } else if (type==2) {
1541      owl_function_adminmsg(buff, perlout);
1542    } else if (type==0) {
1543      return perlout;
1544    } else {
1545      owl_function_popless_text(perlout);
1546    }
1547    owl_free(perlout);
1548  }
1549  return NULL;
1550}
1551
1552
1553void owl_function_change_view(char *filtname) {
1554  owl_view *v;
1555  owl_filter *f;
1556
1557  v=owl_global_get_current_view(&g);
1558  f=owl_global_get_filter(&g, filtname);
1559  if (!f) {
1560    owl_function_makemsg("Unknown filter");
1561    return;
1562  }
1563
1564  owl_view_free(v);
1565  owl_view_create(v, f);
1566
1567  owl_global_set_curmsg(&g, 0);
1568  owl_global_set_curmsg_vert_offset(&g, 0);
1569  owl_global_set_direction_downwards(&g);
1570  owl_function_calculate_topmsg(OWL_DIRECTION_NONE);
1571  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1572}
1573
1574void owl_function_create_filter(int argc, char **argv) {
1575  owl_filter *f;
1576  owl_view *v;
1577  int ret, inuse=0;
1578
1579  if (argc < 2) {
1580    owl_function_makemsg("Wrong number of arguments to filter command");
1581    return;
1582  }
1583
1584  v=owl_global_get_current_view(&g);
1585
1586  /* don't touch the all filter */
1587  if (!strcmp(argv[1], "all")) {
1588    owl_function_makemsg("You may not change the 'all' filter.");
1589    return;
1590  }
1591
1592  /* deal with the case of trying change the filter color */
1593  if (argc==4 && !strcmp(argv[2], "-c")) {
1594    f=owl_global_get_filter(&g, argv[1]);
1595    if (!f) {
1596      owl_function_makemsg("The filter '%s' does not exist.", argv[1]);
1597      return;
1598    }
1599    owl_filter_set_color(f, owl_util_string_to_color(argv[3]));
1600    owl_global_set_needrefresh(&g);
1601    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1602    return;
1603  }
1604
1605  /* create the filter and check for errors */
1606  f=owl_malloc(sizeof(owl_filter));
1607  ret=owl_filter_init(f, argv[1], argc-2, argv+2);
1608  if (ret==-1) {
1609    owl_free(f);
1610    owl_function_makemsg("Invalid filter syntax");
1611    return;
1612  }
1613
1614  /* if the named filter is in use by the current view, remember it */
1615  if (!strcmp(owl_view_get_filtname(v), argv[1])) {
1616    inuse=1;
1617  }
1618
1619  /* if the named filter already exists, nuke it */
1620  if (owl_global_get_filter(&g, argv[1])) {
1621    owl_global_remove_filter(&g, argv[1]);
1622  }
1623
1624  /* add the filter */
1625  owl_global_add_filter(&g, f);
1626
1627  /* if it was in use by the current view then update */
1628  if (inuse) {
1629    owl_function_change_view(argv[1]);
1630  }
1631  owl_global_set_needrefresh(&g);
1632  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1633}
1634
1635void owl_function_show_filters() {
1636  owl_list *l;
1637  owl_filter *f;
1638  int i, j;
1639  owl_fmtext fm;
1640
1641  owl_fmtext_init_null(&fm);
1642
1643  l=owl_global_get_filterlist(&g);
1644  j=owl_list_get_size(l);
1645
1646  owl_fmtext_append_bold(&fm, "Filters:\n");
1647
1648  for (i=0; i<j; i++) {
1649    f=owl_list_get_element(l, i);
1650    owl_fmtext_append_normal(&fm, "   ");
1651    if (owl_global_get_hascolors(&g)) {
1652      owl_fmtext_append_normal_color(&fm, owl_filter_get_name(f), owl_filter_get_color(f));
1653    } else {
1654      owl_fmtext_append_normal(&fm, owl_filter_get_name(f));
1655    }
1656    owl_fmtext_append_normal(&fm, "\n");
1657  }
1658  owl_function_popless_fmtext(&fm);
1659  owl_fmtext_free(&fm);
1660}
1661
1662void owl_function_show_filter(char *name) {
1663  owl_filter *f;
1664  char buff[5000];
1665
1666  f=owl_global_get_filter(&g, name);
1667  if (!f) {
1668    owl_function_makemsg("There is no filter with that name");
1669    return;
1670  }
1671  owl_filter_print(f, buff);
1672  owl_function_popless_text(buff);
1673}
1674
1675void owl_function_show_zpunts() {
1676  owl_filter *f;
1677  owl_list *fl;
1678  char buff[5000];
1679  owl_fmtext fm;
1680  int i, j;
1681
1682  owl_fmtext_init_null(&fm);
1683
1684  fl=owl_global_get_puntlist(&g);
1685  j=owl_list_get_size(fl);
1686  owl_fmtext_append_bold(&fm, "Active zpunt filters:\n");
1687
1688  for (i=0; i<j; i++) {
1689    f=owl_list_get_element(fl, i);
1690    owl_filter_print(f, buff);
1691    owl_fmtext_append_normal(&fm, buff);
1692  }
1693  owl_function_popless_fmtext(&fm);
1694  owl_fmtext_free(&fm);
1695}
1696
1697void owl_function_fastclassinstfilt(char *class, char *instance) {
1698  /* narrow to the current class, instance.  If instance is null then
1699     just narrow to the current class */
1700  owl_list *fl;
1701  owl_filter *f;
1702  char *argbuff, *filtname;
1703  int len;
1704
1705  fl=owl_global_get_filterlist(&g);
1706
1707  /* name for the filter */
1708  len=strlen(class)+30;
1709  if (instance) len+=strlen(instance);
1710  filtname=owl_malloc(len);
1711  if (!instance) {
1712    sprintf(filtname, "class-%s", class);
1713  } else {
1714    sprintf(filtname, "class-%s-instance-%s", class, instance);
1715  }
1716  downstr(filtname);
1717
1718  /* if it already exists then go with it.  This lets users override */
1719  if (owl_global_get_filter(&g, filtname)) {
1720    owl_function_change_view(filtname);
1721    owl_free(filtname);
1722    return;
1723  }
1724
1725  /* create the new filter */
1726  argbuff=owl_malloc(len+20);
1727  sprintf(argbuff, "( class ^%s$ )", class);
1728  if (instance) {
1729    sprintf(argbuff, "%s and ( instance ^%s$ )", argbuff, instance);
1730  }
1731
1732  f=owl_malloc(sizeof(owl_filter));
1733  owl_filter_init_fromstring(f, filtname, argbuff);
1734
1735  /* add it to the global list */
1736  owl_global_add_filter(&g, f);
1737
1738  /* set the current view to use it */
1739  owl_function_change_view(filtname);
1740
1741  owl_free(argbuff);
1742  owl_free(filtname);
1743}
1744
1745void owl_function_fastuserfilt(char *user) {
1746  owl_filter *f;
1747  char *argbuff, *longuser, *shortuser, *filtname;
1748
1749  /* stick the local realm on if it's not there */
1750  longuser=long_sender(user);
1751  shortuser=pretty_sender(user);
1752
1753  /* name for the filter */
1754  filtname=owl_malloc(strlen(shortuser)+20);
1755  sprintf(filtname, "user-%s", shortuser);
1756
1757  /* if it already exists then go with it.  This lets users override */
1758  if (owl_global_get_filter(&g, filtname)) {
1759    owl_function_change_view(filtname);
1760    owl_free(filtname);
1761    return;
1762  }
1763
1764  /* create the new-internal filter */
1765  f=owl_malloc(sizeof(owl_filter));
1766
1767  argbuff=owl_malloc(strlen(longuser)+200);
1768  sprintf(argbuff, "( ( class ^message$ ) and ( instance ^personal$ ) and ( sender ^%s$ ) )", longuser);
1769  sprintf(argbuff, "%s or ( ( type ^admin$ ) and ( recipient %s ) )", argbuff, shortuser);
1770  sprintf(argbuff, "%s or ( ( class ^login$ ) and ( sender ^%s$ ) )", argbuff, longuser);
1771
1772  owl_filter_init_fromstring(f, filtname, argbuff);
1773
1774  /* add it to the global list */
1775  owl_global_add_filter(&g, f);
1776
1777  /* set the current view to use it */
1778  owl_function_change_view(filtname);
1779
1780  /* free stuff */
1781  owl_free(argbuff);
1782  owl_free(filtname);
1783  owl_free(longuser);
1784  owl_free(shortuser);
1785   
1786}
1787
1788/* If flag is 1, marks for deletion.  If flag is 0,
1789 * unmarks for deletion. */
1790void owl_function_delete_curview_msgs(int flag) {
1791  owl_view *v;
1792  int i, j;
1793
1794  v=owl_global_get_current_view(&g);
1795  j=owl_view_get_size(v);
1796  for (i=0; i<j; i++) {
1797    if (flag == 1) {
1798      owl_message_mark_delete(owl_view_get_element(v, i));
1799    } else if (flag == 0) {
1800      owl_message_unmark_delete(owl_view_get_element(v, i));
1801    }
1802  }
1803
1804  owl_function_makemsg("%i messages marked for %sdeletion", j, flag?"":"un");
1805
1806  owl_mainwin_redisplay(owl_global_get_mainwin(&g)); 
1807}
1808
1809void owl_function_smartnarrow(int type) {
1810  /* if the curmsg is a personal message narrow
1811   *    to the converstaion with that user.
1812   * If the curmsg is a class message, instance foo, recip *
1813   *    message, narrow to the class, inst.
1814   * If the curmsg is a class message and type==0 then narrow
1815   *    to the class
1816   * If the curmsg is a class message and type==1 then narrow
1817   *    to the class, instance
1818   */
1819  owl_view *v;
1820  owl_message *m;
1821  char *sender;
1822 
1823  v=owl_global_get_current_view(&g);
1824  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
1825
1826  if (owl_view_get_size(v)==0) {
1827    owl_function_makemsg("No message selected\n");
1828    return;
1829  }
1830
1831  /* for now we skip admin messages. */
1832  if (owl_message_is_admin(m)) {
1833    owl_function_makemsg("Narrowing on an admin message has not been implemented yet.  Check back soon.");
1834    return;
1835  }
1836
1837  /* narrow personal and login messages to the sender */
1838  if (owl_message_is_personal(m) || owl_message_is_login(m)) {
1839    if (owl_message_is_zephyr(m)) {
1840      sender=pretty_sender(owl_message_get_sender(m));
1841      owl_function_fastuserfilt(sender);
1842      free(sender);
1843    }
1844    return;
1845  }
1846
1847  /* narrow class MESSAGE, instance foo, recip * messages to class, inst */
1848  if (!strcasecmp(owl_message_get_class(m), "message") &&
1849      !owl_message_is_personal(m)) {
1850    owl_function_fastclassinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
1851    return;
1852  }
1853
1854  /* otherwise narrow to the class */
1855  if (type==0) {
1856    owl_function_fastclassinstfilt(owl_message_get_class(m), NULL);
1857  } else if (type==1) {
1858    owl_function_fastclassinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
1859  }
1860}
1861
1862void owl_function_color_current_filter(char *color) {
1863  owl_filter *f;
1864  char *name;
1865
1866  name=owl_view_get_filtname(owl_global_get_current_view(&g));
1867  f=owl_global_get_filter(&g, name);
1868  if (!f) {
1869    owl_function_makemsg("Unknown filter");
1870    return;
1871  }
1872
1873  /* don't touch the all filter */
1874  if (!strcmp(name, "all")) {
1875    owl_function_makemsg("You may not change the 'all' filter.");
1876    return;
1877  }
1878
1879  /* deal with the case of trying change the filter color */
1880  owl_filter_set_color(f, owl_util_string_to_color(color));
1881  owl_global_set_needrefresh(&g);
1882  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1883}
1884
1885void owl_function_show_colors() {
1886  owl_fmtext fm;
1887
1888  owl_fmtext_init_null(&fm);
1889  owl_fmtext_append_normal_color(&fm, "default\n", OWL_COLOR_DEFAULT);
1890  owl_fmtext_append_normal_color(&fm, "red\n", OWL_COLOR_RED);
1891  owl_fmtext_append_normal_color(&fm, "green\n", OWL_COLOR_GREEN);
1892  owl_fmtext_append_normal_color(&fm, "yellow\n", OWL_COLOR_YELLOW);
1893  owl_fmtext_append_normal_color(&fm, "blue\n", OWL_COLOR_BLUE);
1894  owl_fmtext_append_normal_color(&fm, "magenta\n", OWL_COLOR_MAGENTA);
1895  owl_fmtext_append_normal_color(&fm, "cyan\n", OWL_COLOR_CYAN);
1896  owl_fmtext_append_normal_color(&fm, "white\n", OWL_COLOR_WHITE);
1897
1898  owl_function_popless_fmtext(&fm);
1899  owl_fmtext_free(&fm);
1900}
1901
1902void owl_function_zpunt(char *class, char *inst, char *recip, int direction) {
1903  /* add the given class, inst, recip to the punt list for filtering.
1904   *   if direction==0 then punt
1905   *   if direction==1 then unpunt */
1906  owl_filter *f;
1907  owl_list *fl;
1908  char *buff;
1909  int ret, i, j;
1910
1911  fl=owl_global_get_puntlist(&g);
1912
1913  /* first, create the filter */
1914  f=malloc(sizeof(owl_filter));
1915  buff=malloc(strlen(class)+strlen(inst)+strlen(recip)+100);
1916  if (!strcmp(recip, "*")) {
1917    sprintf(buff, "class ^%s$ and instance ^%s$", class, inst);
1918  } else {
1919    sprintf(buff, "class ^%s$ and instance ^%s$ and recipient %s", class, inst, recip);
1920  }
1921  owl_function_debugmsg("About to filter %s", buff);
1922  ret=owl_filter_init_fromstring(f, "punt-filter", buff);
1923  owl_free(buff);
1924  if (ret) {
1925    owl_function_makemsg("Error creating filter for zpunt");
1926    owl_filter_free(f);
1927    return;
1928  }
1929
1930  /* Check for an identical filter */
1931  j=owl_list_get_size(fl);
1932  for (i=0; i<j; i++) {
1933    if (owl_filter_equiv(f, owl_list_get_element(fl, i))) {
1934      /* if we're punting, then just silently bow out on this duplicate */
1935      if (direction==0) {
1936        owl_filter_free(f);
1937        return;
1938      }
1939
1940      /* if we're unpunting, then remove this filter from the puntlist */
1941      if (direction==1) {
1942        owl_filter_free(owl_list_get_element(fl, i));
1943        owl_list_remove_element(fl, i);
1944        return;
1945      }
1946    }
1947  }
1948
1949  /* If we're punting, add the filter to the global punt list */
1950  if (direction==0) {
1951    owl_list_append_element(fl, f);
1952  }
1953}
1954
1955void owl_function_activate_keymap(char *keymap) {
1956  if (!owl_keyhandler_activate(owl_global_get_keyhandler(&g), keymap)) {
1957    owl_function_makemsg("Unable to activate keymap '%s'", keymap);
1958  }
1959}
1960
1961
1962void owl_function_show_keymaps() {
1963  owl_list l;
1964  owl_fmtext fm;
1965
1966  owl_fmtext_init_null(&fm);
1967  owl_fmtext_append_bold(&fm, "Keymaps:   ");
1968  owl_fmtext_append_normal(&fm, "(use 'show keymap <name>' for details)\n");
1969  owl_keyhandler_get_keymap_names(owl_global_get_keyhandler(&g), &l);
1970  owl_fmtext_append_list(&fm, &l, "\n", owl_function_keymap_summary);
1971  owl_fmtext_append_normal(&fm, "\n");
1972  owl_function_popless_fmtext(&fm);
1973  owl_keyhandler_keymap_namelist_free(&l);
1974  owl_fmtext_free(&fm);
1975}
1976
1977char *owl_function_keymap_summary(void *name) {
1978  owl_keymap *km
1979    = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
1980  if (km) return owl_keymap_summary(km);
1981  else return(NULL);
1982}
1983
1984/* TODO: implement for real */
1985void owl_function_show_keymap(char *name) {
1986  owl_fmtext  fm;
1987  owl_keymap *km;
1988
1989  owl_fmtext_init_null(&fm);
1990  km = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
1991  if (km) {
1992    owl_keymap_get_details(km, &fm);
1993  } else {
1994    owl_fmtext_append_normal(&fm, "No such keymap...\n");
1995  } 
1996  owl_function_popless_fmtext(&fm);
1997  owl_fmtext_free(&fm);
1998}
1999
2000
2001void owl_function_help_for_command(char *cmdname) {
2002  owl_fmtext   fm;
2003
2004  owl_fmtext_init_null(&fm);
2005  owl_cmd_get_help(owl_global_get_cmddict(&g), cmdname, &fm);
2006  owl_function_popless_fmtext(&fm); 
2007  owl_fmtext_free(&fm);
2008}
Note: See TracBrowser for help on using the repository browser.