source: functions.c @ d309eb3

barnowl_perlaimdebianowlrelease-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since d309eb3 was d309eb3, checked in by James M. Kretchmar <kretch@mit.edu>, 21 years ago
Fixed a memory bug in getsubs Added receive support for zcrypt messages Added the 'zcrypt' variable which controls whether or not zcrypt messages are decrypted 'reply' is disabled for zcrypt until sending zcrypt works Started implementing zcrypt command
  • Property mode set to 100644
File size: 66.9 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 <sys/types.h>
9#include <sys/stat.h>
10#include "owl.h"
11
12static const char fileIdent[] = "$Id$";
13
14void owl_function_noop(void) {
15  return;
16}
17
18char *owl_function_command(char *cmdbuff) {
19  owl_function_debugmsg("executing command: %s", cmdbuff);
20  return owl_cmddict_execute(owl_global_get_cmddict(&g), 
21                             owl_global_get_context(&g), cmdbuff);
22}
23
24void owl_function_command_norv(char *cmdbuff) {
25  char *rv;
26  rv=owl_function_command(cmdbuff);
27  if (rv) owl_free(rv);
28}
29
30void owl_function_command_alias(char *alias_from, char *alias_to) {
31  owl_cmddict_add_alias(owl_global_get_cmddict(&g), alias_from, alias_to);
32}
33
34owl_cmd *owl_function_get_cmd(char *name) {
35  return owl_cmddict_find(owl_global_get_cmddict(&g), name);
36}
37
38void owl_function_show_commands() {
39  owl_list l;
40  owl_fmtext fm;
41
42  owl_fmtext_init_null(&fm);
43  owl_fmtext_append_bold(&fm, "Commands:  ");
44  owl_fmtext_append_normal(&fm, "(use 'show command <name>' for details)\n");
45  owl_cmddict_get_names(owl_global_get_cmddict(&g), &l);
46  owl_fmtext_append_list(&fm, &l, "\n", owl_function_cmd_describe);
47  owl_fmtext_append_normal(&fm, "\n");
48  owl_function_popless_fmtext(&fm);
49  owl_cmddict_namelist_free(&l);
50  owl_fmtext_free(&fm);
51}
52
53char *owl_function_cmd_describe(void *name) {
54  owl_cmd *cmd = owl_cmddict_find(owl_global_get_cmddict(&g), name);
55  if (cmd) return owl_cmd_describe(cmd);
56  else return(NULL);
57}
58
59void owl_function_show_command(char *name) {
60  owl_function_help_for_command(name);
61}
62
63void owl_function_adminmsg(char *header, char *body) {
64  owl_message *m;
65  int followlast;
66
67  followlast=owl_global_should_followlast(&g);
68  m=owl_malloc(sizeof(owl_message));
69  owl_message_create_admin(m, header, body);
70  owl_messagelist_append_element(owl_global_get_msglist(&g), m);
71  owl_view_consider_message(owl_global_get_current_view(&g), m);
72
73  if (followlast) owl_function_lastmsg_noredisplay();
74
75  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
76  if (owl_popwin_is_active(owl_global_get_popwin(&g))) {
77    owl_popwin_refresh(owl_global_get_popwin(&g));
78  }
79 
80  wnoutrefresh(owl_global_get_curs_recwin(&g));
81  owl_global_set_needrefresh(&g);
82}
83
84void owl_function_make_outgoing_zephyr(char *body, char *zwriteline, char *zsig) {
85  owl_message *m;
86  int followlast;
87  owl_zwrite z;
88 
89  followlast=owl_global_should_followlast(&g);
90
91  /* create a zwrite for the purpose of filling in other message fields */
92  owl_zwrite_create_from_line(&z, zwriteline);
93
94  /* create the message */
95  m=owl_malloc(sizeof(owl_message));
96  owl_message_create_from_zwriteline(m, zwriteline, body, zsig);
97
98  /* add it to the global list and current view */
99  owl_messagelist_append_element(owl_global_get_msglist(&g), m);
100  owl_view_consider_message(owl_global_get_current_view(&g), m);
101
102  if (followlast) owl_function_lastmsg_noredisplay();
103
104  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
105  if (owl_popwin_is_active(owl_global_get_popwin(&g))) {
106    owl_popwin_refresh(owl_global_get_popwin(&g));
107  }
108 
109  wnoutrefresh(owl_global_get_curs_recwin(&g));
110  owl_global_set_needrefresh(&g);
111  owl_zwrite_free(&z);
112}
113
114void owl_function_zwrite_setup(char *line) {
115  owl_editwin *e;
116  char buff[1024];
117  owl_zwrite z;
118  int ret;
119
120  /* check the arguments */
121  ret=owl_zwrite_create_from_line(&z, line);
122  if (ret) {
123    owl_function_makemsg("Error in zwrite arugments");
124    owl_zwrite_free(&z);
125    return;
126  }
127
128  /* send a ping if necessary */
129  if (owl_global_is_txping(&g)) {
130    owl_zwrite_send_ping(&z);
131  }
132  owl_zwrite_free(&z);
133
134  /* create and setup the editwin */
135  e=owl_global_get_typwin(&g);
136  owl_editwin_new_style(e, OWL_EDITWIN_STYLE_MULTILINE, owl_global_get_msg_history(&g));
137
138  if (!owl_global_get_lockout_ctrld(&g)) {
139    owl_function_makemsg("Type your zephyr below.  End with ^D or a dot on a line by itself.  ^C will quit.");
140  } else {
141    owl_function_makemsg("Type your zephyr below.  End with a dot on a line by itself.  ^C will quit.");
142  }
143
144  owl_editwin_clear(e);
145  owl_editwin_set_dotsend(e);
146  strcpy(buff, "----> ");
147  strcat(buff, line);
148  strcat(buff, "\n");
149  owl_editwin_set_locktext(e, buff);
150
151  /* make it active */
152  owl_global_set_typwin_active(&g);
153}
154
155void owl_function_zcrypt_setup(char *line) {
156  owl_editwin *e;
157  char buff[1024];
158  owl_zwrite z;
159  int ret;
160
161  /* check the arguments */
162  ret=owl_zwrite_create_from_line(&z, line);
163  if (ret) {
164    owl_function_makemsg("Error in zwrite arugments");
165    owl_zwrite_free(&z);
166    return;
167  }
168
169  if (owl_zwrite_get_numrecips(&z)>0) {
170    owl_function_makemsg("You may not specifiy a recipient for a zcrypt message");
171    owl_zwrite_free(&z);
172    return;
173  }
174
175  /* send a ping if necessary */
176  if (owl_global_is_txping(&g)) {
177    owl_zwrite_send_ping(&z);
178  }
179  owl_zwrite_free(&z);
180
181  /* create and setup the editwin */
182  e=owl_global_get_typwin(&g);
183  owl_editwin_new_style(e, OWL_EDITWIN_STYLE_MULTILINE, owl_global_get_msg_history(&g));
184
185  if (!owl_global_get_lockout_ctrld(&g)) {
186    owl_function_makemsg("Type your zephyr below.  End with ^D or a dot on a line by itself.  ^C will quit.");
187  } else {
188    owl_function_makemsg("Type your zephyr below.  End with a dot on a line by itself.  ^C will quit.");
189  }
190
191  owl_editwin_clear(e);
192  owl_editwin_set_dotsend(e);
193  strcpy(buff, "----> ");
194  strcat(buff, line);
195  strcat(buff, "\n");
196  owl_editwin_set_locktext(e, buff);
197
198  /* make it active */
199  owl_global_set_typwin_active(&g);
200}
201
202void owl_function_zwrite(char *line) {
203  owl_zwrite z;
204  int i, j;
205
206  /* create the zwrite and send the message */
207  owl_zwrite_create_from_line(&z, line);
208  owl_zwrite_send_message(&z, owl_editwin_get_text(owl_global_get_typwin(&g)));
209  owl_function_makemsg("Waiting for ack...");
210
211  /* display the message as an outgoing message in the receive window */
212  if (owl_global_is_displayoutgoing(&g) && owl_zwrite_is_personal(&z)) {
213    owl_function_make_outgoing_zephyr(owl_editwin_get_text(owl_global_get_typwin(&g)), line, owl_zwrite_get_zsig(&z));
214  }
215
216  /* log it if we have logging turned on */
217  if (owl_global_is_logging(&g) && owl_zwrite_is_personal(&z)) {
218    j=owl_zwrite_get_numrecips(&z);
219    for (i=0; i<j; i++) {
220      owl_log_outgoing(owl_zwrite_get_recip_n(&z, i),
221                       owl_editwin_get_text(owl_global_get_typwin(&g)));
222    }
223  }
224
225  /* free the zwrite */
226  owl_zwrite_free(&z);
227}
228
229
230/* If filter is non-null, looks for the next message matching
231 * that filter.  If skip_deleted, skips any deleted messages.
232 * If last_if_none, will stop at the last message in the view
233 * if no matching messages are found.  */
234void owl_function_nextmsg_full(char *filter, int skip_deleted, int last_if_none) {
235  int curmsg, i, viewsize, found;
236  owl_view *v;
237  owl_filter *f = NULL;
238  owl_message *m;
239
240  v=owl_global_get_current_view(&g);
241
242  if (filter) {
243    f=owl_global_get_filter(&g, filter);
244    if (!f) {
245      owl_function_makemsg("No %s filter defined", filter);
246      return;
247    }
248  }
249
250  curmsg=owl_global_get_curmsg(&g);
251  viewsize=owl_view_get_size(v);
252  found=0;
253
254  /* just check to make sure we're in bounds... */
255  if (curmsg>viewsize-1) curmsg=viewsize-1;
256  if (curmsg<0) curmsg=0;
257
258  for (i=curmsg+1; i<viewsize; i++) {
259    m=owl_view_get_element(v, i);
260    if (skip_deleted && owl_message_is_delete(m)) continue;
261    if (f && !owl_filter_message_match(f, m)) continue;
262    found = 1;
263    break;
264  }
265
266  if (i>owl_view_get_size(v)-1) i=owl_view_get_size(v)-1;
267
268  if (!found) {
269    owl_function_makemsg("already at last%s message%s%s",
270                         skip_deleted?" non-deleted":"",
271                         filter?" in ":"", filter?filter:"");
272    /* if (!skip_deleted) owl_function_beep(); */
273  }
274
275  if (last_if_none || found) {
276    owl_global_set_curmsg(&g, i);
277    owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
278    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
279    owl_global_set_direction_downwards(&g);
280  }
281}
282
283void owl_function_prevmsg_full(char *filter, int skip_deleted, int first_if_none) {
284  int curmsg, i, viewsize, found;
285  owl_view *v;
286  owl_filter *f = NULL;
287  owl_message *m;
288
289  v=owl_global_get_current_view(&g);
290
291  if (filter) {
292    f=owl_global_get_filter(&g, filter);
293    if (!f) {
294      owl_function_makemsg("No %s filter defined", filter);
295      return;
296    }
297  }
298
299  curmsg=owl_global_get_curmsg(&g);
300  viewsize=owl_view_get_size(v);
301  found=0;
302
303  /* just check to make sure we're in bounds... */
304  if (curmsg<0) curmsg=0;
305
306  for (i=curmsg-1; i>=0; i--) {
307    m=owl_view_get_element(v, i);
308    if (skip_deleted && owl_message_is_delete(m)) continue;
309    if (f && !owl_filter_message_match(f, m)) continue;
310    found = 1;
311    break;
312  }
313
314  if (i<0) i=0;
315
316  if (!found) {
317    owl_function_makemsg("already at first%s message%s%s",
318                         skip_deleted?" non-deleted":"",
319                         filter?" in ":"", filter?filter:"");
320    /* if (!skip_deleted) owl_function_beep(); */
321  }
322
323  if (first_if_none || found) {
324    owl_global_set_curmsg(&g, i);
325    owl_function_calculate_topmsg(OWL_DIRECTION_UPWARDS);
326    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
327    owl_global_set_direction_upwards(&g);
328  }
329}
330
331void owl_function_nextmsg() {
332  owl_function_nextmsg_full(NULL, 0, 1);
333}
334
335
336void owl_function_prevmsg() {
337  owl_function_prevmsg_full(NULL, 0, 1);
338}
339
340void owl_function_nextmsg_notdeleted() {
341  owl_function_nextmsg_full(NULL, 1, 1);
342}
343
344void owl_function_prevmsg_notdeleted() {
345  owl_function_prevmsg_full(NULL, 1, 1);
346}
347
348
349void owl_function_nextmsg_personal() {
350  owl_function_nextmsg_full("personal", 0, 0);
351}
352
353void owl_function_prevmsg_personal() {
354  owl_function_prevmsg_full("personal", 0, 0);
355}
356
357
358/* if move_after is 1, moves after the delete */
359void owl_function_deletecur(int move_after) {
360  int curmsg;
361  owl_view *v;
362
363  v=owl_global_get_current_view(&g);
364
365  /* bail if there's no current message */
366  if (owl_view_get_size(v) < 1) {
367    owl_function_makemsg("No current message to delete");
368    return;
369  }
370
371  /* mark the message for deletion */
372  curmsg=owl_global_get_curmsg(&g);
373  owl_view_delete_element(v, curmsg);
374
375  if (move_after) {
376    /* move the poiner in the appropriate direction
377     * to the next undeleted msg */
378    if (owl_global_get_direction(&g)==OWL_DIRECTION_UPWARDS) {
379      owl_function_prevmsg_notdeleted();
380    } else {
381      owl_function_nextmsg_notdeleted();
382    }
383  }
384}
385
386
387void owl_function_undeletecur(int move_after) {
388  int curmsg;
389  owl_view *v;
390
391  v=owl_global_get_current_view(&g);
392 
393  if (owl_view_get_size(v) < 1) {
394    owl_function_makemsg("No current message to undelete");
395    return;
396  }
397  curmsg=owl_global_get_curmsg(&g);
398
399  owl_view_undelete_element(v, curmsg);
400
401  if (move_after) {
402    if (owl_global_get_direction(&g)==OWL_DIRECTION_UPWARDS) {
403      if (curmsg>0) {
404        owl_function_prevmsg();
405      } else {
406        owl_function_nextmsg();
407      }
408    } else {
409      owl_function_nextmsg();
410    }
411  }
412
413  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
414}
415
416
417void owl_function_expunge() {
418  int curmsg;
419  owl_message *m;
420  owl_messagelist *ml;
421  owl_view *v;
422  int lastmsgid=0;
423
424  curmsg=owl_global_get_curmsg(&g);
425  v=owl_global_get_current_view(&g);
426  ml=owl_global_get_msglist(&g);
427
428  m=owl_view_get_element(v, curmsg);
429  if (m) lastmsgid = owl_message_get_id(m);
430
431  /* expunge the message list */
432  owl_messagelist_expunge(ml);
433
434  /* update all views (we only have one right now) */
435  owl_view_recalculate(v);
436
437  /* find where the new position should be
438     (as close as possible to where we last where) */
439  curmsg = owl_view_get_nearest_to_msgid(v, lastmsgid);
440  if (curmsg>owl_view_get_size(v)-1) curmsg = owl_view_get_size(v)-1;
441  if (curmsg<0) curmsg = 0;
442  owl_global_set_curmsg(&g, curmsg);
443  owl_function_calculate_topmsg(OWL_DIRECTION_NONE);
444  /* if there are no messages set the direction to down in case we
445     delete everything upwards */
446  owl_global_set_direction_downwards(&g);
447 
448  owl_function_makemsg("Messages expunged");
449  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
450}
451
452
453void owl_function_firstmsg() {
454  owl_global_set_curmsg(&g, 0);
455  owl_global_set_topmsg(&g, 0);
456  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
457  owl_global_set_direction_downwards(&g);
458}
459
460void owl_function_lastmsg_noredisplay() {
461  int oldcurmsg, curmsg;
462  owl_view *v;
463
464  v=owl_global_get_current_view(&g);
465  oldcurmsg=owl_global_get_curmsg(&g);
466  curmsg=owl_view_get_size(v)-1; 
467  if (curmsg<0) curmsg=0;
468  owl_global_set_curmsg(&g, curmsg);
469  if (oldcurmsg < curmsg) {
470    owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
471  } else if (curmsg<owl_view_get_size(v)) {
472    /* If already at the end, blank the screen and move curmsg
473     * past the end of the messages. */
474    owl_global_set_topmsg(&g, curmsg+1);
475    owl_global_set_curmsg(&g, curmsg+1);
476  } 
477  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
478  owl_global_set_direction_downwards(&g);
479}
480
481void owl_function_lastmsg() {
482  owl_function_lastmsg_noredisplay();
483  owl_mainwin_redisplay(owl_global_get_mainwin(&g)); 
484}
485
486void owl_function_shift_right() {
487  owl_global_set_rightshift(&g, owl_global_get_rightshift(&g)+10);
488  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
489  owl_global_set_needrefresh(&g);
490}
491
492
493void owl_function_shift_left() {
494  int shift;
495
496  shift=owl_global_get_rightshift(&g);
497  if (shift>=10) {
498    owl_global_set_rightshift(&g, shift-10);
499    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
500    owl_global_set_needrefresh(&g);
501  } else {
502    owl_function_beep();
503    owl_function_makemsg("Already full left");
504  }
505}
506
507
508void owl_function_unsuball() {
509  unsuball();
510  owl_function_makemsg("Unsubscribed from all messages.");
511}
512
513void owl_function_loadsubs(char *file) {
514  int ret;
515  ret=owl_zephyr_loadsubs(file);
516  if (ret==0) {
517    owl_function_makemsg("Subscribed to messages from file.");
518  } else if (ret==-1) {
519    owl_function_makemsg("Could not open file.");
520  } else {
521    owl_function_makemsg("Error subscribing to messages from file.");
522  }
523}
524
525void owl_function_suspend() {
526  endwin();
527  printf("\n");
528  kill(getpid(), SIGSTOP);
529
530  /* resize to reinitialize all the windows when we come back */
531  owl_command_resize();
532}
533
534void owl_function_zaway_toggle() {
535  if (!owl_global_is_zaway(&g)) {
536    owl_global_set_zaway_msg(&g, owl_global_get_zaway_msg_default(&g));
537    owl_function_zaway_on();
538  } else {
539    owl_function_zaway_off();
540  }
541}
542
543void owl_function_zaway_on() {
544  owl_global_set_zaway_on(&g);
545  owl_function_makemsg("zaway set (%s)", owl_global_get_zaway_msg(&g));
546}
547
548void owl_function_zaway_off() {
549  owl_global_set_zaway_off(&g);
550  owl_function_makemsg("zaway off");
551}
552
553void owl_function_quit() {
554  char *ret;
555 
556  /* zlog out if we need to */
557  if (owl_global_is_shutdownlogout(&g)) {
558    owl_function_zlog_out();
559  }
560
561  /* execute the commands in shutdown */
562  ret = owl_config_execute("owl::shutdown();");
563  if (ret) owl_free(ret);
564
565  /* final clean up */
566  unsuball();
567  ZClosePort();
568  endwin();
569  owl_function_debugmsg("Quitting Owl");
570  exit(0);
571}
572
573
574void owl_function_zlog_in() {
575  char *exposure, *eset;
576  int ret;
577
578  eset=EXPOSE_REALMVIS;
579  exposure=ZGetVariable("exposure");
580  if (exposure==NULL) {
581    eset=EXPOSE_REALMVIS;
582  } else if (!strcasecmp(exposure,EXPOSE_NONE)) {
583    eset = EXPOSE_NONE;
584  } else if (!strcasecmp(exposure,EXPOSE_OPSTAFF)) {
585    eset = EXPOSE_OPSTAFF;
586  } else if (!strcasecmp(exposure,EXPOSE_REALMVIS)) {
587    eset = EXPOSE_REALMVIS;
588  } else if (!strcasecmp(exposure,EXPOSE_REALMANN)) {
589    eset = EXPOSE_REALMANN;
590  } else if (!strcasecmp(exposure,EXPOSE_NETVIS)) {
591    eset = EXPOSE_NETVIS;
592  } else if (!strcasecmp(exposure,EXPOSE_NETANN)) {
593    eset = EXPOSE_NETANN;
594  }
595   
596  ret=ZSetLocation(eset);
597  if (ret != ZERR_NONE) {
598    /*
599      char buff[LINE];
600      sprintf(buff, "Error setting location: %s", error_message(ret));
601      owl_function_makemsg(buff);
602    */
603  }
604}
605
606void owl_function_zlog_out() {
607  int ret;
608 
609  ret=ZUnsetLocation();
610  if (ret != ZERR_NONE) {
611    /*
612      char buff[LINE];
613      sprintf(buff, "Error unsetting location: %s", error_message(ret));
614      owl_function_makemsg(buff);
615    */
616  }
617}
618
619
620void owl_function_makemsg(char *fmt, ...) {
621  va_list ap;
622  char buff[2048];
623
624  va_start(ap, fmt);
625  werase(owl_global_get_curs_msgwin(&g));
626 
627  vsnprintf(buff, 2048, fmt, ap);
628  owl_function_debugmsg("makemsg: %s", buff);
629  waddstr(owl_global_get_curs_msgwin(&g), buff); 
630  wnoutrefresh(owl_global_get_curs_msgwin(&g));
631  owl_global_set_needrefresh(&g);
632  va_end(ap);
633}
634
635void owl_function_errormsg(char *fmt, ...) {
636  va_list ap;
637  char buff[2048];
638
639  va_start(ap, fmt);
640  werase(owl_global_get_curs_msgwin(&g));
641 
642  vsnprintf(buff, 2048, fmt, ap);
643  owl_function_debugmsg("ERROR: %s", buff);
644  waddstr(owl_global_get_curs_msgwin(&g), buff); 
645  waddstr(owl_global_get_curs_msgwin(&g), "ERROR: "); 
646  wnoutrefresh(owl_global_get_curs_msgwin(&g));
647  owl_global_set_needrefresh(&g);
648  va_end(ap);
649}
650
651
652void owl_function_openurl() {
653  /* visit the first url in the current message */
654  owl_message *m;
655  owl_view *v;
656  char *ptr1, *ptr2, *text, url[LINE], tmpbuff[LINE];
657  int webbrowser;
658
659  webbrowser = owl_global_get_webbrowser(&g);
660
661  if (webbrowser < 0 || webbrowser == OWL_WEBBROWSER_NONE) {
662    owl_function_makemsg("No browser selected");
663    return;
664  }
665
666  v=owl_global_get_current_view(&g);
667 
668  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
669
670  if (!m || owl_view_get_size(v)==0) {
671    owl_function_makemsg("No current message selected");
672    return;
673  }
674
675  text=owl_message_get_text(m);
676
677  /* First look for a good URL */ 
678  if ((ptr1=strstr(text, "http://"))!=NULL) {
679    ptr2=strpbrk(ptr1, " \n\t");
680    if (ptr2) {
681      strncpy(url, ptr1, ptr2-ptr1+1);
682      url[ptr2-ptr1+1]='\0';
683    } else {
684      strcpy(url, ptr1);
685    }
686
687    /* if we had <http strip a trailing > */
688    if (ptr1>text && ptr1[-1]=='<') {
689      if (url[strlen(url)-1]=='>') {
690        url[strlen(url)-1]='\0';
691      }
692    }
693  } else if ((ptr1=strstr(text, "https://"))!=NULL) {
694    /* Look for an https URL */ 
695    ptr2=strpbrk(ptr1, " \n\t");
696    if (ptr2) {
697      strncpy(url, ptr1, ptr2-ptr1+1);
698      url[ptr2-ptr1+1]='\0';
699    } else {
700      strcpy(url, ptr1);
701    }
702   
703    /* if we had <http strip a trailing > */
704    if (ptr1>text && ptr1[-1]=='<') {
705      if (url[strlen(url)-1]=='>') {
706        url[strlen(url)-1]='\0';
707      }
708    }
709  } else if ((ptr1=strstr(text, "www."))!=NULL) {
710    /* if we can't find a real url look for www.something */
711    ptr2=strpbrk(ptr1, " \n\t");
712    if (ptr2) {
713      strncpy(url, ptr1, ptr2-ptr1+1);
714      url[ptr2-ptr1+1]='\0';
715    } else {
716      strcpy(url, ptr1);
717    }
718  } else {
719    owl_function_beep();
720    owl_function_makemsg("Could not find URL to open.");
721    return;
722  }
723
724  /* Make sure there aren't any quotes or \'s in the url */
725  for (ptr1 = url; *ptr1; ptr1++) {
726    if (*ptr1 == '"' || *ptr1 == '\\') {
727      owl_function_beep();
728      owl_function_makemsg("URL contains invalid characters.");
729      return;
730    }
731  }
732 
733  /* NOTE: There are potentially serious security issues here... */
734
735  /* open the page */
736  owl_function_makemsg("Opening %s", url);
737  if (webbrowser == OWL_WEBBROWSER_NETSCAPE) {
738    snprintf(tmpbuff, LINE, "netscape -remote \"openURL(%s)\" > /dev/null 2> /dev/null", url);
739    system(tmpbuff); 
740  } else if (webbrowser == OWL_WEBBROWSER_GALEON) {
741    snprintf(tmpbuff, LINE, "galeon \"%s\" > /dev/null 2> /dev/null &", url);
742    system(tmpbuff); 
743  } else if (webbrowser == OWL_WEBBROWSER_OPERA) {
744    snprintf(tmpbuff, LINE, "opera \"%s\" > /dev/null 2> /dev/null &", url);
745    system(tmpbuff); 
746  }
747}
748
749void owl_function_calculate_topmsg(int direction) {
750  int recwinlines, topmsg, curmsg;
751  owl_view *v;
752
753  v=owl_global_get_current_view(&g);
754  curmsg=owl_global_get_curmsg(&g);
755  topmsg=owl_global_get_topmsg(&g);
756  recwinlines=owl_global_get_recwin_lines(&g);
757
758  /*
759  if (owl_view_get_size(v) < 1) {
760    return;
761  }
762  */
763
764  switch (owl_global_get_scrollmode(&g)) {
765  case OWL_SCROLLMODE_TOP:
766    topmsg = owl_function_calculate_topmsg_top(direction, v, curmsg, topmsg, recwinlines);
767    break;
768  case OWL_SCROLLMODE_NEARTOP:
769    topmsg = owl_function_calculate_topmsg_neartop(direction, v, curmsg, topmsg, recwinlines);
770    break;
771  case OWL_SCROLLMODE_CENTER:
772    topmsg = owl_function_calculate_topmsg_center(direction, v, curmsg, topmsg, recwinlines);
773    break;
774  case OWL_SCROLLMODE_PAGED:
775    topmsg = owl_function_calculate_topmsg_paged(direction, v, curmsg, topmsg, recwinlines, 0);
776    break;
777  case OWL_SCROLLMODE_PAGEDCENTER:
778    topmsg = owl_function_calculate_topmsg_paged(direction, v, curmsg, topmsg, recwinlines, 1);
779    break;
780  case OWL_SCROLLMODE_NORMAL:
781  default:
782    topmsg = owl_function_calculate_topmsg_normal(direction, v, curmsg, topmsg, recwinlines);
783  }
784  owl_function_debugmsg("Calculated a topmsg of %i", topmsg);
785  owl_global_set_topmsg(&g, topmsg);
786}
787
788/* Returns what the new topmsg should be. 
789 * Passed the last direction of movement,
790 * the current view,
791 * the current message number in the view,
792 * the top message currently being displayed,
793 * and the number of lines in the recwin.
794 */
795int owl_function_calculate_topmsg_top(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines) {
796  return(curmsg);
797}
798
799int owl_function_calculate_topmsg_neartop(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines) {
800  if (curmsg>0 
801      && (owl_message_get_numlines(owl_view_get_element(v, curmsg-1))
802          <  recwinlines/2)) {
803    return(curmsg-1);
804  } else {
805    return(curmsg);
806  }
807}
808 
809int owl_function_calculate_topmsg_center(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines) {
810  int i, last, lines;
811
812  last = curmsg;
813  lines = 0;
814  for (i=curmsg-1; i>=0; i--) {
815    lines += owl_message_get_numlines(owl_view_get_element(v, i));
816    if (lines > recwinlines/2) break;
817    last = i;
818  }
819  return(last);
820}
821 
822int owl_function_calculate_topmsg_paged(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines, int center_on_page) {
823  int i, last, lines, savey;
824 
825  /* If we're off the top of the screen, scroll up such that the
826   * curmsg is near the botton of the screen. */
827  if (curmsg < topmsg) {
828    last = curmsg;
829    lines = 0;
830    for (i=curmsg; i>=0; i--) {
831      lines += owl_message_get_numlines(owl_view_get_element(v, i));
832      if (lines > recwinlines) break;
833    last = i;
834    }
835    if (center_on_page) {
836      return(owl_function_calculate_topmsg_center(direction, v, curmsg, 0, recwinlines));
837    } else {
838      return(last);
839    }
840  }
841
842  /* Find number of lines from top to bottom of curmsg (store in savey) */
843  savey=0;
844  for (i=topmsg; i<=curmsg; i++) {
845    savey+=owl_message_get_numlines(owl_view_get_element(v, i));
846  }
847
848  /* if we're off the bottom of the screen, scroll down */
849  if (savey > recwinlines) {
850    if (center_on_page) {
851      return(owl_function_calculate_topmsg_center(direction, v, curmsg, 0, recwinlines));
852    } else {
853      return(curmsg);
854    }
855  }
856
857  /* else just stay as we are... */
858  return(topmsg);
859}
860
861
862int owl_function_calculate_topmsg_normal(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines) {
863  int savey, j, i, foo, y;
864
865  if (curmsg<0) return(topmsg);
866   
867  /* If we're off the top of the screen then center */
868  if (curmsg<topmsg) {
869    topmsg=owl_function_calculate_topmsg_center(direction, v, curmsg, 0, recwinlines);
870  }
871
872  /* Find number of lines from top to bottom of curmsg (store in savey) */
873  savey=0;
874  for (i=topmsg; i<=curmsg; i++) {
875    savey+=owl_message_get_numlines(owl_view_get_element(v, i));
876  }
877
878  /* If we're off the bottom of the screen, set the topmsg to curmsg
879   * and scroll upwards */
880  if (savey > recwinlines) {
881    topmsg=curmsg;
882    savey=owl_message_get_numlines(owl_view_get_element(v, i));
883    direction=OWL_DIRECTION_UPWARDS;
884  }
885 
886  /* If our bottom line is less than 1/4 down the screen then scroll up */
887  if (direction == OWL_DIRECTION_UPWARDS || direction == OWL_DIRECTION_NONE) {
888    if (savey < (recwinlines / 4)) {
889      y=0;
890      for (j=curmsg; j>=0; j--) {
891        foo=owl_message_get_numlines(owl_view_get_element(v, j));
892        /* will we run the curmsg off the screen? */
893        if ((foo+y) >= recwinlines) {
894          j++;
895          if (j>curmsg) j=curmsg;
896          break;
897        }
898        /* have saved 1/2 the screen space? */
899        y+=foo;
900        if (y > (recwinlines / 2)) break;
901      }
902      if (j<0) j=0;
903      return(j);
904    }
905  }
906
907  if (direction == OWL_DIRECTION_DOWNWARDS || direction == OWL_DIRECTION_NONE) {
908    /* If curmsg bottom line is more than 3/4 down the screen then scroll down */
909    if (savey > ((recwinlines * 3)/4)) {
910      y=0;
911      /* count lines from the top until we can save 1/2 the screen size */
912      for (j=topmsg; j<curmsg; j++) {
913        y+=owl_message_get_numlines(owl_view_get_element(v, j));
914        if (y > (recwinlines / 2)) break;
915      }
916      if (j==curmsg) {
917        j--;
918      }
919      return(j+1);
920    }
921  }
922
923  return(topmsg);
924}
925
926
927void owl_function_resize() {
928  owl_global_set_resize_pending(&g);
929}
930
931
932void owl_function_run_buffercommand() {
933  char *buff;
934
935  buff=owl_global_get_buffercommand(&g);
936  if (!strncmp(buff, "zwrite ", 7)) {
937
938    owl_function_zwrite(buff);
939  }
940}
941
942void owl_function_debugmsg(char *fmt, ...) {
943  FILE *file;
944  time_t now;
945  char buff1[LINE], buff2[LINE];
946  va_list ap;
947  va_start(ap, fmt);
948
949  if (!owl_global_is_debug_fast(&g)) return;
950
951  file=fopen(owl_global_get_debug_file(&g), "a");
952  if (!file) return;
953
954  now=time(NULL);
955  strcpy(buff1, ctime(&now));
956  buff1[strlen(buff1)-1]='\0';
957
958  owl_global_get_runtime_string(&g, buff2);
959 
960  fprintf(file, "[%i -  %s - %s]: ", (int) getpid(), buff1, buff2);
961  vfprintf(file, fmt, ap);
962  fprintf(file, "\n");
963  fclose(file);
964
965  va_end(ap);
966}
967
968
969void owl_function_refresh() {
970  owl_function_resize();
971}
972
973void owl_function_beep() {
974  if (owl_global_is_bell(&g)) {
975    beep();
976    owl_global_set_needrefresh(&g); /* do we really need this? */
977  }
978}
979
980
981void owl_function_subscribe(char *class, char *inst, char *recip) {
982  int ret;
983
984  ret=owl_zephyr_sub(class, inst, recip);
985  if (ret) {
986    owl_function_makemsg("Error subscribing.");
987  } else {
988    owl_function_makemsg("Subscribed.");
989  }
990}
991
992
993void owl_function_unsubscribe(char *class, char *inst, char *recip) {
994  int ret;
995
996  ret=owl_zephyr_unsub(class, inst, recip);
997  if (ret) {
998    owl_function_makemsg("Error subscribing.");
999  } else {
1000    owl_function_makemsg("Unsubscribed.");
1001  }
1002}
1003
1004
1005void owl_function_set_cursor(WINDOW *win) {
1006  wnoutrefresh(win);
1007}
1008
1009
1010void owl_function_full_redisplay() {
1011  redrawwin(owl_global_get_curs_recwin(&g));
1012  redrawwin(owl_global_get_curs_sepwin(&g));
1013  redrawwin(owl_global_get_curs_typwin(&g));
1014  redrawwin(owl_global_get_curs_msgwin(&g));
1015
1016  wnoutrefresh(owl_global_get_curs_recwin(&g));
1017  wnoutrefresh(owl_global_get_curs_sepwin(&g));
1018  wnoutrefresh(owl_global_get_curs_typwin(&g));
1019  wnoutrefresh(owl_global_get_curs_msgwin(&g));
1020 
1021  sepbar("");
1022  owl_function_makemsg("");
1023
1024  owl_global_set_needrefresh(&g);
1025}
1026
1027
1028void owl_function_popless_text(char *text) {
1029  owl_popwin *pw;
1030  owl_viewwin *v;
1031
1032  pw=owl_global_get_popwin(&g);
1033  v=owl_global_get_viewwin(&g);
1034
1035  owl_popwin_up(pw);
1036  owl_viewwin_init_text(v, owl_popwin_get_curswin(pw),
1037                        owl_popwin_get_lines(pw), owl_popwin_get_cols(pw),
1038                        text);
1039  owl_popwin_refresh(pw);
1040  owl_viewwin_redisplay(v, 0);
1041  owl_global_set_needrefresh(&g);
1042}
1043
1044
1045void owl_function_popless_fmtext(owl_fmtext *fm) {
1046  owl_popwin *pw;
1047  owl_viewwin *v;
1048
1049  pw=owl_global_get_popwin(&g);
1050  v=owl_global_get_viewwin(&g);
1051
1052  owl_popwin_up(pw);
1053  owl_viewwin_init_fmtext(v, owl_popwin_get_curswin(pw),
1054                   owl_popwin_get_lines(pw), owl_popwin_get_cols(pw),
1055                   fm);
1056  owl_popwin_refresh(pw);
1057  owl_viewwin_redisplay(v, 0);
1058  owl_global_set_needrefresh(&g);
1059}
1060
1061void owl_function_about() {
1062  char buff[5000];
1063
1064  sprintf(buff, "This is owl version %s\n", OWL_VERSION_STRING);
1065  strcat(buff, "\nOwl was written by James Kretchmar at the Massachusetts\n");
1066  strcat(buff, "Institute of Technology.  The first version, 0.5, was\n");
1067  strcat(buff, "released in March 2002.\n");
1068  strcat(buff, "\n");
1069  strcat(buff, "The name 'owl' was chosen in reference to the owls in the\n");
1070  strcat(buff, "Harry Potter novels, who are tasked with carrying messages\n");
1071  strcat(buff, "between Witches and Wizards.\n");
1072  strcat(buff, "\n");
1073  strcat(buff, "Copyright 2002 Massachusetts Institute of Technology\n");
1074  strcat(buff, "\n");
1075  strcat(buff, "Permission to use, copy, modify, and distribute this\n");
1076  strcat(buff, "software and its documentation for any purpose and without\n");
1077  strcat(buff, "fee is hereby granted, provided that the above copyright\n");
1078  strcat(buff, "notice and this permission notice appear in all copies\n");
1079  strcat(buff, "and in supporting documentation.  No representation is\n");
1080  strcat(buff, "made about the suitability of this software for any\n");
1081  strcat(buff, "purpose.  It is provided \"as is\" without express\n");
1082  strcat(buff, "or implied warranty.\n");
1083  owl_function_popless_text(buff);
1084}
1085
1086void owl_function_info() {
1087  owl_message *m;
1088  ZNotice_t *n;
1089  char buff[5000], tmpbuff[1024];
1090  char *ptr;
1091  int i, j, fields, len;
1092  owl_view *v;
1093
1094  v=owl_global_get_current_view(&g);
1095  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
1096  if (!m || owl_view_get_size(v)==0) {
1097    owl_function_makemsg("No message selected\n");
1098    return;
1099  }
1100
1101  sprintf(buff,     "Msg Id    : %i\n", owl_message_get_id(m));
1102  if (owl_message_is_type_zephyr(m)) {
1103    sprintf(buff, "%sType      : zephyr\n", buff);
1104  } else if (owl_message_is_type_admin(m)) {
1105    sprintf(buff, "%sType      : admin\n", buff);
1106  } else if (owl_message_is_type_generic(m)) {
1107    sprintf(buff, "%sType      : generic\n", buff);
1108  } else {
1109    sprintf(buff, "%sType      : unknown\n", buff);
1110  }
1111  if (owl_message_is_direction_in(m)) {
1112    sprintf(buff, "%sDirection : in\n", buff);
1113  } else if (owl_message_is_direction_out(m)) {
1114    sprintf(buff, "%sDirection : out\n", buff);
1115  } else if (owl_message_is_direction_none(m)) {
1116    sprintf(buff, "%sDirection : none\n", buff);
1117  } else {
1118    sprintf(buff, "%sDirection : unknown\n", buff);
1119  }
1120  sprintf(buff, "%sTime      : %s\n", buff, owl_message_get_timestr(m));
1121
1122  if (!owl_message_is_type_zephyr(m)) {
1123    owl_function_popless_text(buff);
1124    return;
1125  }
1126
1127
1128  if (owl_message_is_direction_out(m)) {
1129    sprintf(buff, "%sClass     : %s\n", buff, owl_message_get_class(m));
1130    sprintf(buff, "%sInstance  : %s\n", buff, owl_message_get_instance(m));
1131    sprintf(buff, "%sSender    : %s\n", buff, owl_message_get_sender(m));
1132    sprintf(buff, "%sRecip     : %s\n", buff, owl_message_get_recipient(m));
1133    sprintf(buff, "%sOpcode    : %s\n", buff, owl_message_get_opcode(m));
1134   
1135    owl_function_popless_text(buff);
1136    return;
1137  }
1138
1139  n=owl_message_get_notice(m);
1140
1141  sprintf(buff, "%sClass     : %s\n", buff, owl_message_get_class(m));
1142  sprintf(buff, "%sInstance  : %s\n", buff, owl_message_get_instance(m));
1143  sprintf(buff, "%sSender    : %s\n", buff, owl_message_get_sender(m));
1144  sprintf(buff, "%sRecip     : %s\n", buff, owl_message_get_recipient(m));
1145  sprintf(buff, "%sOpcode    : %s\n", buff, owl_message_get_opcode(m));
1146  strcat(buff,    "Kind      : ");
1147  if (n->z_kind==UNSAFE) {
1148    strcat(buff, "UNSAFE\n");
1149  } else if (n->z_kind==UNACKED) {
1150    strcat(buff, "UNACKED\n");
1151  } else if (n->z_kind==ACKED) {
1152    strcat(buff, "ACKED\n");
1153  } else if (n->z_kind==HMACK) {
1154    strcat(buff, "HMACK\n");
1155  } else if (n->z_kind==HMCTL) {
1156    strcat(buff, "HMCTL\n");
1157  } else if (n->z_kind==SERVACK) {
1158    strcat(buff, "SERVACK\n");
1159  } else if (n->z_kind==SERVNAK) {
1160    strcat(buff, "SERVNAK\n");
1161  } else if (n->z_kind==CLIENTACK) {
1162    strcat(buff, "CLIENTACK\n");
1163  } else if (n->z_kind==STAT) {
1164    strcat(buff, "STAT\n");
1165  } else {
1166    strcat(buff, "ILLEGAL VALUE\n");
1167  }
1168  sprintf(buff, "%sTime      : %s\n", buff, owl_message_get_timestr(m));
1169  sprintf(buff, "%sHost      : %s\n", buff, owl_message_get_hostname(m));
1170  sprintf(buff, "%sPort      : %i\n", buff, n->z_port);
1171  strcat(buff,    "Auth      : ");
1172  if (n->z_auth == ZAUTH_FAILED) {
1173    strcat(buff, "FAILED\n");
1174  } else if (n->z_auth == ZAUTH_NO) {
1175    strcat(buff, "NO\n");
1176  } else if (n->z_auth == ZAUTH_YES) {
1177    strcat(buff, "YES\n");
1178  } else {
1179    sprintf(buff, "%sUnknown State (%i)\n", buff, n->z_auth);
1180  }
1181  sprintf(buff, "%sCheckd Ath: %i\n", buff, n->z_checked_auth);
1182  sprintf(buff, "%sMulti notc: %s\n", buff, n->z_multinotice);
1183  sprintf(buff, "%sNum other : %i\n", buff, n->z_num_other_fields);
1184  sprintf(buff, "%sMsg Len   : %i\n", buff, n->z_message_len);
1185
1186  sprintf(buff, "%sFields    : %i\n", buff, owl_zephyr_get_num_fields(n));
1187
1188  fields=owl_zephyr_get_num_fields(n);
1189  for (i=0; i<fields; i++) {
1190    sprintf(buff, "%sField %i   : ", buff, i+1);
1191
1192    ptr=owl_zephyr_get_field(n, i+1, &len);
1193    if (!ptr) break;
1194    if (len<30) {
1195      strncpy(tmpbuff, ptr, len);
1196      tmpbuff[len]='\0';
1197    } else {
1198      strncpy(tmpbuff, ptr, 30);
1199      tmpbuff[30]='\0';
1200      strcat(tmpbuff, "...");
1201    }
1202
1203    /* just for testing for now */
1204    for (j=0; j<strlen(tmpbuff); j++) {
1205      if (tmpbuff[j]=='\n') tmpbuff[j]='~';
1206      if (tmpbuff[j]=='\r') tmpbuff[j]='!';
1207    }
1208
1209    strcat(buff, tmpbuff);
1210    strcat(buff, "\n");
1211  }
1212  sprintf(buff, "%sDefault Fm: %s\n", buff, n->z_default_format);
1213       
1214  owl_function_popless_text(buff);
1215}
1216
1217
1218void owl_function_curmsg_to_popwin() {
1219  owl_popwin *pw;
1220  owl_view *v;
1221  owl_message *m;
1222
1223  v = owl_global_get_current_view(&g);
1224
1225  pw=owl_global_get_popwin(&g);
1226
1227  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
1228
1229  if (!m || owl_view_get_size(v)==0) {
1230    owl_function_makemsg("No current message");
1231    return;
1232  }
1233
1234  owl_function_popless_fmtext(owl_message_get_fmtext(m));
1235}
1236
1237
1238void owl_function_page_curmsg(int step) {
1239  /* scroll down or up within the current message IF the message is truncated */
1240
1241  int offset, curmsg, lines;
1242  owl_view *v;
1243  owl_message *m;
1244
1245  offset=owl_global_get_curmsg_vert_offset(&g);
1246  v=owl_global_get_current_view(&g);
1247  curmsg=owl_global_get_curmsg(&g);
1248  m=owl_view_get_element(v, curmsg);
1249  if (!m || owl_view_get_size(v)==0) return;
1250  lines=owl_message_get_numlines(m);
1251
1252  if (offset==0) {
1253    /* Bail if the curmsg isn't the last one displayed */
1254    if (curmsg != owl_mainwin_get_last_msg(owl_global_get_mainwin(&g))) {
1255      owl_function_makemsg("The entire message is already displayed");
1256      return;
1257    }
1258   
1259    /* Bail if we're not truncated */
1260    if (!owl_mainwin_is_curmsg_truncated(owl_global_get_mainwin(&g))) {
1261      owl_function_makemsg("The entire message is already displayed");
1262      return;
1263    }
1264  }
1265 
1266 
1267  /* don't scroll past the last line */
1268  if (step>0) {
1269    if (offset+step > lines-1) {
1270      owl_global_set_curmsg_vert_offset(&g, lines-1);
1271    } else {
1272      owl_global_set_curmsg_vert_offset(&g, offset+step);
1273    }
1274  }
1275
1276  /* would we be before the beginning of the message? */
1277  if (step<0) {
1278    if (offset+step<0) {
1279      owl_global_set_curmsg_vert_offset(&g, 0);
1280    } else {
1281      owl_global_set_curmsg_vert_offset(&g, offset+step);
1282    }
1283  }
1284 
1285  /* redisplay */
1286  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1287  owl_global_set_needrefresh(&g);
1288}
1289
1290void owl_function_resize_typwin(int newsize) {
1291  owl_global_set_typwin_lines(&g, newsize);
1292  owl_function_resize();
1293}
1294
1295void owl_function_typwin_grow() {
1296  int i;
1297
1298  i=owl_global_get_typwin_lines(&g);
1299  owl_function_resize_typwin(i+1);
1300}
1301
1302void owl_function_typwin_shrink() {
1303  int i;
1304
1305  i=owl_global_get_typwin_lines(&g);
1306  if (i>2) {
1307    owl_function_resize_typwin(i-1);
1308  }
1309}
1310
1311void owl_function_mainwin_pagedown() {
1312  int i;
1313
1314  i=owl_mainwin_get_last_msg(owl_global_get_mainwin(&g));
1315  if (i<0) return;
1316  if (owl_mainwin_is_last_msg_truncated(owl_global_get_mainwin(&g))
1317      && (owl_global_get_curmsg(&g) < i)
1318      && (i>0)) {
1319    i--;
1320  }
1321  owl_global_set_curmsg(&g, i);
1322  owl_function_nextmsg();
1323}
1324
1325void owl_function_mainwin_pageup() {
1326  owl_global_set_curmsg(&g, owl_global_get_topmsg(&g));
1327  owl_function_prevmsg();
1328}
1329
1330void owl_function_getsubs() {
1331  int ret, num, i, one;
1332  ZSubscription_t sub;
1333  char *buff, *tmpbuff;
1334
1335  one = 1;
1336
1337  ret=ZRetrieveSubscriptions(0, &num);
1338  if (ret == ZERR_TOOMANYSUBS) {
1339    owl_function_makemsg("Zephyr: too many subscriptions");
1340    return;
1341  }
1342
1343  buff=owl_malloc(num*500);
1344  tmpbuff=owl_malloc(num*500);
1345  strcpy(buff, "");
1346  for (i=0; i<num; i++) {
1347    if ((ret = ZGetSubscriptions(&sub, &one)) != ZERR_NONE) {
1348      owl_function_makemsg("Error while getting subscriptions");
1349      owl_free(buff);
1350      owl_free(tmpbuff);
1351      ZFlushSubscriptions();
1352      return;
1353    } else {
1354      sprintf(tmpbuff, "<%s,%s,%s>\n%s", sub.zsub_class, sub.zsub_classinst, sub.zsub_recipient, buff);
1355      strcpy(buff, tmpbuff);
1356    }
1357  }
1358
1359  owl_function_popless_text(buff);
1360  owl_free(buff);
1361  owl_free(tmpbuff);
1362  ZFlushSubscriptions();
1363}
1364
1365#define PABUFLEN 5000
1366void owl_function_printallvars() {
1367  char buff[PABUFLEN], *pos, *name;
1368  owl_list varnames;
1369  int i, numvarnames, rem;
1370
1371  pos = buff;
1372  pos += sprintf(pos, "%-20s = %s\n", "VARIABLE", "VALUE");
1373  pos += sprintf(pos, "%-20s   %s\n",  "--------", "-----");
1374  owl_variable_dict_get_names(owl_global_get_vardict(&g), &varnames);
1375  rem = (buff+PABUFLEN)-pos-1;
1376  numvarnames = owl_list_get_size(&varnames);
1377  for (i=0; i<numvarnames; i++) {
1378    name = owl_list_get_element(&varnames, i);
1379    if (name && name[0]!='_') {
1380      rem = (buff+PABUFLEN)-pos-1;   
1381      pos += snprintf(pos, rem, "\n%-20s = ", name);
1382      rem = (buff+PABUFLEN)-pos-1;   
1383      owl_variable_get_tostring(owl_global_get_vardict(&g), name, pos, rem);
1384      pos = buff+strlen(buff);
1385    }
1386  }
1387  rem = (buff+PABUFLEN)-pos-1;   
1388  snprintf(pos, rem, "\n");
1389  owl_variable_dict_namelist_free(&varnames);
1390 
1391  owl_function_popless_text(buff);
1392}
1393
1394void owl_function_show_variables() {
1395  owl_list varnames;
1396  owl_fmtext fm; 
1397  int i, numvarnames;
1398  char *varname;
1399
1400  owl_fmtext_init_null(&fm);
1401  owl_fmtext_append_bold(&fm, 
1402      "Variables: (use 'show variable <name>' for details)\n");
1403  owl_variable_dict_get_names(owl_global_get_vardict(&g), &varnames);
1404  numvarnames = owl_list_get_size(&varnames);
1405  for (i=0; i<numvarnames; i++) {
1406    varname = owl_list_get_element(&varnames, i);
1407    if (varname && varname[0]!='_') {
1408      owl_variable_describe(owl_global_get_vardict(&g), varname, &fm);
1409    }
1410  }
1411  owl_variable_dict_namelist_free(&varnames);
1412  owl_function_popless_fmtext(&fm);
1413  owl_fmtext_free(&fm);
1414}
1415
1416void owl_function_show_variable(char *name) {
1417  owl_fmtext fm; 
1418
1419  owl_fmtext_init_null(&fm);
1420  owl_variable_get_help(owl_global_get_vardict(&g), name, &fm);
1421  owl_function_popless_fmtext(&fm);
1422  owl_fmtext_free(&fm); 
1423}
1424
1425/* note: this applies to global message list, not to view.
1426 * If flag is 1, deletes.  If flag is 0, undeletes. */
1427void owl_function_delete_by_id(int id, int flag) {
1428  owl_messagelist *ml;
1429  owl_message *m;
1430  ml = owl_global_get_msglist(&g);
1431  m = owl_messagelist_get_by_id(ml, id);
1432  if (m) {
1433    if (flag == 1) {
1434      owl_message_mark_delete(m);
1435    } else if (flag == 0) {
1436      owl_message_unmark_delete(m);
1437    }
1438    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1439    owl_global_set_needrefresh(&g);
1440  } else {
1441    owl_function_makemsg("No message with id %d: unable to mark for (un)delete",id);
1442  }
1443}
1444
1445void owl_function_delete_automsgs() {
1446  /* mark for deletion all messages in the current view that match the
1447   * 'trash' filter */
1448
1449  int i, j, count;
1450  owl_message *m;
1451  owl_view *v;
1452  owl_filter *f;
1453
1454  /* get the trash filter */
1455  f=owl_global_get_filter(&g, "trash");
1456  if (!f) {
1457    owl_function_makemsg("No trash filter defined");
1458    return;
1459  }
1460
1461  v=owl_global_get_current_view(&g);
1462
1463  count=0;
1464  j=owl_view_get_size(v);
1465  for (i=0; i<j; i++) {
1466    m=owl_view_get_element(v, i);
1467    if (owl_filter_message_match(f, m)) {
1468      count++;
1469      owl_message_mark_delete(m);
1470    }
1471  }
1472  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1473  owl_function_makemsg("%i messages marked for deletion", count);
1474  owl_global_set_needrefresh(&g);
1475}
1476
1477
1478void owl_function_status() {
1479  char buff[5000];
1480  time_t start;
1481  int up, days, hours, minutes;
1482
1483  start=owl_global_get_starttime(&g);
1484
1485  sprintf(buff, "Version: %s\n", OWL_VERSION_STRING);
1486  sprintf(buff, "%sScreen size: %i lines, %i columns\n", buff, owl_global_get_lines(&g), owl_global_get_cols(&g));
1487  sprintf(buff, "%sStartup Arugments: %s\n", buff, owl_global_get_startupargs(&g));
1488  sprintf(buff, "%sStartup Time: %s", buff, ctime(&start));
1489
1490  up=owl_global_get_runtime(&g);
1491  days=up/86400;
1492  up-=days*86400;
1493  hours=up/3600;
1494  up-=hours*3600;
1495  minutes=up/60;
1496  up-=minutes*60;
1497  sprintf(buff, "%sRun Time: %i days %2.2i:%2.2i:%2.2i\n", buff, days, hours, minutes, up);
1498
1499  if (owl_global_get_hascolors(&g)) {
1500    sprintf(buff, "%sColor: Yes, %i color pairs.\n", buff, owl_global_get_colorpairs(&g));
1501  } else {
1502    strcat(buff, "Color: No.\n");
1503  }
1504 
1505  owl_function_popless_text(buff);
1506}
1507
1508void owl_function_show_term() {
1509  owl_fmtext fm;
1510  char buff[LINE];
1511
1512  owl_fmtext_init_null(&fm);
1513  sprintf(buff, "Terminal Lines: %i\nTerminal Columns: %i\n",
1514          owl_global_get_lines(&g),
1515          owl_global_get_cols(&g));
1516  owl_fmtext_append_normal(&fm, buff);
1517
1518  if (owl_global_get_hascolors(&g)) {
1519    owl_fmtext_append_normal(&fm, "Color: Yes\n");
1520    sprintf(buff, "Number of color pairs: %i\n", owl_global_get_colorpairs(&g));
1521    owl_fmtext_append_normal(&fm, buff);
1522    sprintf(buff, "Can change colors: %s\n", can_change_color() ? "yes" : "no");
1523    owl_fmtext_append_normal(&fm, buff);
1524  } else {
1525    owl_fmtext_append_normal(&fm, "Color: No\n");
1526  }
1527
1528  owl_function_popless_fmtext(&fm);
1529  owl_fmtext_free(&fm);
1530}
1531
1532
1533void owl_function_reply(int type, int enter) {
1534  /* if type = 0 then normal reply.
1535   * if type = 1 then it's a reply to sender
1536   * if enter = 0 then allow the command to be edited
1537   * if enter = 1 then don't wait for editing
1538   */
1539  char *buff, *oldbuff;
1540  owl_message *m;
1541  owl_filter *f;
1542 
1543  if (owl_view_get_size(owl_global_get_current_view(&g))==0) {
1544    owl_function_makemsg("No message selected");
1545  } else {
1546    char *class, *inst, *to, *cc=NULL;
1547   
1548    m=owl_view_get_element(owl_global_get_current_view(&g), owl_global_get_curmsg(&g));
1549    if (!m) {
1550      owl_function_makemsg("No message selected");
1551      return;
1552    }
1553
1554    /* first check if we catch the reply-lockout filter */
1555    f=owl_global_get_filter(&g, "reply-lockout");
1556    if (f) {
1557      if (owl_filter_message_match(f, m)) {
1558        owl_function_makemsg("Sorry, replies to this message have been disabled by the reply-lockout filter");
1559        return;
1560      }
1561    }
1562
1563    /* for now we disable replies to zcrypt messages, since we can't
1564       support an encrypted reply */
1565    if (!strcasecmp(owl_message_get_opcode(m), "crypt")) {
1566      owl_function_makemsg("Replies to zcrypt messages are not enabled in this release");
1567      return;
1568    }
1569
1570    if (owl_message_is_direction_out(m)) {
1571      owl_function_zwrite_setup(owl_message_get_zwriteline(m));
1572      owl_global_set_buffercommand(&g, owl_message_get_zwriteline(m));
1573    } else if (owl_message_is_type_admin(m)) {
1574      owl_function_makemsg("You cannot reply to an admin message");
1575    } else {
1576      if (owl_message_is_login(m)) {
1577        class="MESSAGE";
1578        inst="PERSONAL";
1579        to=owl_message_get_sender(m);
1580      } else if (type==1) {
1581        class="MESSAGE";
1582        inst="PERSONAL";
1583        to=owl_message_get_sender(m);
1584      } else {
1585        class=owl_message_get_class(m);
1586        inst=owl_message_get_instance(m);
1587        to=owl_message_get_recipient(m);
1588        cc=owl_message_get_cc(m);
1589        if (!strcmp(to, "") || !strcmp(to, "*")) {
1590          to="";
1591        } else if (to[0]=='@') {
1592          /* leave it, to get the realm */
1593        } else {
1594          to=owl_message_get_sender(m);
1595        }
1596      }
1597     
1598      /* create the command line */
1599      buff = owl_strdup("zwrite");
1600      if (strcasecmp(class, "message")) {
1601        buff = owl_sprintf("%s -c %s%s%s", oldbuff=buff, owl_getquoting(class), class, owl_getquoting(class));
1602        owl_free(oldbuff);
1603      }
1604      if (strcasecmp(inst, "personal")) {
1605        buff = owl_sprintf("%s -i %s%s%s", oldbuff=buff, owl_getquoting(inst), inst, owl_getquoting(inst));
1606        owl_free(oldbuff);
1607      }
1608      if (*to != '\0') {
1609        char *tmp, *oldtmp, *tmp2;
1610        tmp=short_zuser(to);
1611        if (cc) {
1612          tmp = owl_util_uniq(oldtmp=tmp, cc, "-");
1613          owl_free(oldtmp);
1614          buff = owl_sprintf("%s -C %s", oldbuff=buff, tmp);
1615          owl_free(oldbuff);
1616        } else {
1617          if (owl_global_is_smartstrip(&g)) {
1618            tmp2=tmp;
1619            tmp=smartstripped_user(tmp2);
1620            owl_free(tmp2);
1621          }
1622          buff = owl_sprintf("%s %s", oldbuff=buff, tmp);
1623          owl_free(oldbuff);
1624        }
1625        owl_free(tmp);
1626      }
1627      if (cc) owl_free(cc);
1628
1629      if (enter) {
1630        owl_history *hist = owl_global_get_cmd_history(&g);
1631        owl_history_store(hist, buff);
1632        owl_history_reset(hist);
1633        owl_function_command_norv(buff);
1634      } else {
1635        owl_function_start_command(buff);
1636      }
1637      owl_free(buff);
1638    }
1639  }
1640}
1641
1642void owl_function_zlocate(int argc, char **argv, int auth) {
1643  owl_fmtext fm;
1644  char *ptr, buff[LINE];
1645  int i;
1646
1647  owl_fmtext_init_null(&fm);
1648
1649  for (i=0; i<argc; i++) {
1650    ptr=long_zuser(argv[i]);
1651    owl_zephyr_zlocate(ptr, buff, auth);
1652    owl_fmtext_append_normal(&fm, buff);
1653    owl_free(ptr);
1654  }
1655
1656  owl_function_popless_fmtext(&fm);
1657  owl_fmtext_free(&fm);
1658}
1659
1660void owl_function_start_command(char *line) {
1661  int i, j;
1662  owl_editwin *tw;
1663
1664  tw=owl_global_get_typwin(&g);
1665  owl_global_set_typwin_active(&g);
1666  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, 
1667                        owl_global_get_cmd_history(&g));
1668
1669  owl_editwin_set_locktext(tw, "command: ");
1670  owl_global_set_needrefresh(&g);
1671
1672  j=strlen(line);
1673  for (i=0; i<j; i++) {
1674    owl_editwin_process_char(tw, line[i]);
1675  }
1676  owl_editwin_redisplay(tw, 0);
1677}
1678
1679char *owl_function_exec(int argc, char **argv, char *buff, int type) {
1680  /* if type == 1 display in a popup
1681   * if type == 2 display an admin messages
1682   * if type == 0 return output
1683   * else display in a popup
1684   */
1685  char *newbuff, *redirect = " 2>&1 < /dev/null";
1686  char *out, buff2[1024];
1687  int size;
1688  FILE *p;
1689
1690  if (argc<2) {
1691    owl_function_makemsg("Wrong number of arguments to the exec command");
1692    return NULL;
1693  }
1694
1695  buff = skiptokens(buff, 1);
1696  newbuff = owl_malloc(strlen(buff)+strlen(redirect)+1);
1697  strcpy(newbuff, buff);
1698  strcat(newbuff, redirect);
1699
1700  p=popen(newbuff, "r");
1701  out=owl_malloc(1024);
1702  size=1024;
1703  strcpy(out, "");
1704  while (fgets(buff2, 1024, p)!=NULL) {
1705    size+=1024;
1706    out=owl_realloc(out, size);
1707    strcat(out, buff2);
1708  }
1709  pclose(p);
1710
1711  if (type==1) {
1712    owl_function_popless_text(out);
1713  } else if (type==0) {
1714    return out;
1715  } else if (type==2) {
1716    owl_function_adminmsg(buff, out);
1717  } else {
1718    owl_function_popless_text(out);
1719  }
1720  owl_free(out);
1721  return NULL;
1722}
1723
1724
1725char *owl_function_perl(int argc, char **argv, char *buff, int type) {
1726  /* if type == 1 display in a popup
1727   * if type == 2 display an admin messages
1728   * if type == 0 return output
1729   * else display in a popup
1730   */
1731  char *perlout;
1732
1733  if (argc<2) {
1734    owl_function_makemsg("Wrong number of arguments to perl command");
1735    return NULL;
1736  }
1737
1738  /* consume first token (argv[0]) */
1739  buff = skiptokens(buff, 1);
1740
1741  perlout = owl_config_execute(buff);
1742  if (perlout) { 
1743    if (type==1) {
1744      owl_function_popless_text(perlout);
1745    } else if (type==2) {
1746      owl_function_adminmsg(buff, perlout);
1747    } else if (type==0) {
1748      return perlout;
1749    } else {
1750      owl_function_popless_text(perlout);
1751    }
1752    owl_free(perlout);
1753  }
1754  return NULL;
1755}
1756
1757
1758void owl_function_change_view(char *filtname) {
1759  owl_view *v;
1760  owl_filter *f;
1761  int curid=-1, newpos, curmsg;
1762  owl_message *curm=NULL;
1763
1764  v=owl_global_get_current_view(&g);
1765  curmsg=owl_global_get_curmsg(&g);
1766  if (curmsg==-1) {
1767    owl_function_debugmsg("Hit the curmsg==-1 case in change_view");
1768  } else {
1769    curm=owl_view_get_element(v, curmsg);
1770    if (curm) {
1771      curid=owl_message_get_id(curm);
1772      owl_view_save_curmsgid(v, curid);
1773    }
1774  }
1775
1776  /* grab the filter */;
1777  f=owl_global_get_filter(&g, filtname);
1778  if (!f) {
1779    owl_function_makemsg("Unknown filter");
1780    return;
1781  }
1782
1783  /* free the existing view and create a new one based on the filter */
1784  owl_view_free(v);
1785  owl_view_create(v, f);
1786
1787  /* Figure out what to set the current message to.
1788   * - If the view we're leaving has messages in it, go to the closest message
1789   *   to the last message pointed to in that view.
1790   * - If the view we're leaving is empty, try to restore the position
1791   *   from the last time we were in the new view.  */
1792  if (curm) {
1793    newpos = owl_view_get_nearest_to_msgid(v, curid);
1794  } else {
1795    newpos = owl_view_get_nearest_to_saved(v);
1796  }
1797
1798  owl_global_set_curmsg(&g, newpos);
1799
1800  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
1801  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1802  owl_global_set_direction_downwards(&g);
1803}
1804
1805void owl_function_create_filter(int argc, char **argv) {
1806  owl_filter *f;
1807  owl_view *v;
1808  int ret, inuse=0;
1809
1810  if (argc < 2) {
1811    owl_function_makemsg("Wrong number of arguments to filter command");
1812    return;
1813  }
1814
1815  v=owl_global_get_current_view(&g);
1816
1817  /* don't touch the all filter */
1818  if (!strcmp(argv[1], "all")) {
1819    owl_function_makemsg("You may not change the 'all' filter.");
1820    return;
1821  }
1822
1823  /* deal with the case of trying change the filter color */
1824  if (argc==4 && !strcmp(argv[2], "-c")) {
1825    f=owl_global_get_filter(&g, argv[1]);
1826    if (!f) {
1827      owl_function_makemsg("The filter '%s' does not exist.", argv[1]);
1828      return;
1829    }
1830    owl_filter_set_color(f, owl_util_string_to_color(argv[3]));
1831    owl_global_set_needrefresh(&g);
1832    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1833    return;
1834  }
1835
1836  /* create the filter and check for errors */
1837  f=owl_malloc(sizeof(owl_filter));
1838  ret=owl_filter_init(f, argv[1], argc-2, argv+2);
1839  if (ret==-1) {
1840    owl_free(f);
1841    owl_function_makemsg("Invalid filter syntax");
1842    return;
1843  }
1844
1845  /* if the named filter is in use by the current view, remember it */
1846  if (!strcmp(owl_view_get_filtname(v), argv[1])) {
1847    inuse=1;
1848  }
1849
1850  /* if the named filter already exists, nuke it */
1851  if (owl_global_get_filter(&g, argv[1])) {
1852    owl_global_remove_filter(&g, argv[1]);
1853  }
1854
1855  /* add the filter */
1856  owl_global_add_filter(&g, f);
1857
1858  /* if it was in use by the current view then update */
1859  if (inuse) {
1860    owl_function_change_view(argv[1]);
1861  }
1862  owl_global_set_needrefresh(&g);
1863  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1864}
1865
1866void owl_function_show_filters() {
1867  owl_list *l;
1868  owl_filter *f;
1869  int i, j;
1870  owl_fmtext fm;
1871
1872  owl_fmtext_init_null(&fm);
1873
1874  l=owl_global_get_filterlist(&g);
1875  j=owl_list_get_size(l);
1876
1877  owl_fmtext_append_bold(&fm, "Filters:\n");
1878
1879  for (i=0; i<j; i++) {
1880    f=owl_list_get_element(l, i);
1881    owl_fmtext_append_normal(&fm, "   ");
1882    if (owl_global_get_hascolors(&g)) {
1883      owl_fmtext_append_normal_color(&fm, owl_filter_get_name(f), owl_filter_get_color(f));
1884    } else {
1885      owl_fmtext_append_normal(&fm, owl_filter_get_name(f));
1886    }
1887    owl_fmtext_append_normal(&fm, "\n");
1888  }
1889  owl_function_popless_fmtext(&fm);
1890  owl_fmtext_free(&fm);
1891}
1892
1893void owl_function_show_filter(char *name) {
1894  owl_filter *f;
1895  char buff[5000];
1896
1897  f=owl_global_get_filter(&g, name);
1898  if (!f) {
1899    owl_function_makemsg("There is no filter with that name");
1900    return;
1901  }
1902  owl_filter_print(f, buff);
1903  owl_function_popless_text(buff);
1904}
1905
1906void owl_function_show_zpunts() {
1907  owl_filter *f;
1908  owl_list *fl;
1909  char buff[5000];
1910  owl_fmtext fm;
1911  int i, j;
1912
1913  owl_fmtext_init_null(&fm);
1914
1915  fl=owl_global_get_puntlist(&g);
1916  j=owl_list_get_size(fl);
1917  owl_fmtext_append_bold(&fm, "Active zpunt filters:\n");
1918
1919  for (i=0; i<j; i++) {
1920    f=owl_list_get_element(fl, i);
1921    owl_filter_print(f, buff);
1922    owl_fmtext_append_normal(&fm, buff);
1923  }
1924  owl_function_popless_fmtext(&fm);
1925  owl_fmtext_free(&fm);
1926}
1927
1928char *owl_function_fastclassinstfilt(char *class, char *instance) {
1929  /* creates a filter for a class, instance if one doesn't exist.
1930   * If instance is null then apply for all messgaes in the class.
1931   * returns the name of the filter, which the caller must free.*/
1932  owl_list *fl;
1933  owl_filter *f;
1934  char *argbuff, *filtname;
1935  int len;
1936
1937  fl=owl_global_get_filterlist(&g);
1938
1939  /* name for the filter */
1940  len=strlen(class)+30;
1941  if (instance) len+=strlen(instance);
1942  filtname=owl_malloc(len);
1943  if (!instance) {
1944    sprintf(filtname, "class-%s", class);
1945  } else {
1946    sprintf(filtname, "class-%s-instance-%s", class, instance);
1947  }
1948  downstr(filtname);
1949
1950  /* if it already exists then go with it.  This lets users override */
1951  if (owl_global_get_filter(&g, filtname)) {
1952    return filtname;
1953  }
1954
1955  /* create the new filter */
1956  argbuff=owl_malloc(len+20);
1957  sprintf(argbuff, "( class ^%s$ )", class);
1958  if (instance) {
1959    sprintf(argbuff, "%s and ( instance ^%s$ )", argbuff, instance);
1960  }
1961
1962  f=owl_malloc(sizeof(owl_filter));
1963  owl_filter_init_fromstring(f, filtname, argbuff);
1964
1965  /* add it to the global list */
1966  owl_global_add_filter(&g, f);
1967
1968  owl_free(argbuff);
1969  return filtname;
1970}
1971
1972char *owl_function_fastuserfilt(char *user) {
1973  owl_filter *f;
1974  char *argbuff, *longuser, *shortuser, *filtname;
1975
1976  /* stick the local realm on if it's not there */
1977  longuser=long_zuser(user);
1978  shortuser=short_zuser(user);
1979
1980  /* name for the filter */
1981  filtname=owl_malloc(strlen(shortuser)+20);
1982  sprintf(filtname, "user-%s", shortuser);
1983
1984  /* if it already exists then go with it.  This lets users override */
1985  if (owl_global_get_filter(&g, filtname)) {
1986    return filtname;
1987  }
1988
1989  /* create the new-internal filter */
1990  f=owl_malloc(sizeof(owl_filter));
1991
1992  argbuff=owl_malloc(strlen(longuser)+1000);
1993  sprintf(argbuff, "( type ^zephyr$ and ( class ^message$ and instance ^personal$ and ");
1994  sprintf(argbuff, "%s ( ( direction ^in$ and sender ^%s$ ) or ( direction ^out$ and recipient ^%s$ ) ) )", argbuff, longuser, longuser);
1995  sprintf(argbuff, "%s or ( ( class ^login$ ) and ( sender ^%s$ ) ) )", argbuff, longuser);
1996
1997  owl_filter_init_fromstring(f, filtname, argbuff);
1998
1999  /* add it to the global list */
2000  owl_global_add_filter(&g, f);
2001
2002  /* free stuff */
2003  owl_free(argbuff);
2004  owl_free(longuser);
2005  owl_free(shortuser);
2006
2007  return filtname;
2008}
2009
2010char *owl_function_fasttypefilt(char *type) {
2011  owl_filter *f;
2012  char *argbuff, *filtname;
2013
2014  /* name for the filter */
2015  filtname=owl_sprintf("type-%s", type);
2016
2017  /* if it already exists then go with it.  This lets users override */
2018  if (owl_global_get_filter(&g, filtname)) {
2019    return filtname;
2020  }
2021
2022  /* create the new-internal filter */
2023  f=owl_malloc(sizeof(owl_filter));
2024
2025  argbuff = owl_sprintf("type ^%s$", type);
2026
2027  owl_filter_init_fromstring(f, filtname, argbuff);
2028
2029  /* add it to the global list */
2030  owl_global_add_filter(&g, f);
2031
2032  /* free stuff */
2033  owl_free(argbuff);
2034
2035  return filtname;
2036}
2037
2038/* If flag is 1, marks for deletion.  If flag is 0,
2039 * unmarks for deletion. */
2040void owl_function_delete_curview_msgs(int flag) {
2041  owl_view *v;
2042  int i, j;
2043
2044  v=owl_global_get_current_view(&g);
2045  j=owl_view_get_size(v);
2046  for (i=0; i<j; i++) {
2047    if (flag == 1) {
2048      owl_message_mark_delete(owl_view_get_element(v, i));
2049    } else if (flag == 0) {
2050      owl_message_unmark_delete(owl_view_get_element(v, i));
2051    }
2052  }
2053
2054  owl_function_makemsg("%i messages marked for %sdeletion", j, flag?"":"un");
2055
2056  owl_mainwin_redisplay(owl_global_get_mainwin(&g)); 
2057}
2058
2059char *owl_function_smartfilter(int type) {
2060  /* Returns the name of a filter, or null.  The caller
2061   * must free this name.  */
2062  /* if the curmsg is a personal message return a filter name
2063   *    to the converstaion with that user.
2064   * If the curmsg is a class message, instance foo, recip *
2065   *    message, return a filter name to the class, inst.
2066   * If the curmsg is a class message and type==0 then
2067   *    return a filter name for just the class.
2068   * If the curmsg is a class message and type==1 then
2069   *    return a filter name for the class and instance.
2070   */
2071  owl_view *v;
2072  owl_message *m;
2073  char *zperson, *filtname=NULL;
2074 
2075  v=owl_global_get_current_view(&g);
2076  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2077
2078  if (!m || owl_view_get_size(v)==0) {
2079    owl_function_makemsg("No message selected\n");
2080    return(NULL);
2081  }
2082
2083  /* very simple handling of admin messages for now */
2084  if (owl_message_is_type_admin(m)) {
2085    return(owl_function_fasttypefilt("admin"));
2086  }
2087
2088  /* narrow personal and login messages to the sender or recip as appropriate */
2089  if (owl_message_is_personal(m) || owl_message_is_login(m)) {
2090    if (owl_message_is_type_zephyr(m)) {
2091      if (owl_message_is_direction_in(m)) {
2092        zperson=short_zuser(owl_message_get_sender(m));
2093      } else {
2094        zperson=short_zuser(owl_message_get_recipient(m));
2095      }
2096      filtname=owl_function_fastuserfilt(zperson);
2097      owl_free(zperson);
2098      return(filtname);
2099    }
2100    return(NULL);
2101  }
2102
2103  /* narrow class MESSAGE, instance foo, recip * messages to class, inst */
2104  if (!strcasecmp(owl_message_get_class(m), "message") &&
2105      !owl_message_is_personal(m)) {
2106    filtname=owl_function_fastclassinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2107    return(filtname);
2108  }
2109
2110  /* otherwise narrow to the class */
2111  if (type==0) {
2112    filtname=owl_function_fastclassinstfilt(owl_message_get_class(m), NULL);
2113  } else if (type==1) {
2114    filtname=owl_function_fastclassinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2115  }
2116  return(filtname);
2117}
2118
2119void owl_function_smartzpunt(int type) {
2120  /* Starts a zpunt command based on the current class,instance pair.
2121   * If type=0, uses just class.  If type=1, uses instance as well. */
2122  owl_view *v;
2123  owl_message *m;
2124  char *cmd, *cmdprefix, *mclass, *minst;
2125 
2126  v=owl_global_get_current_view(&g);
2127  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2128
2129  if (!m || owl_view_get_size(v)==0) {
2130    owl_function_makemsg("No message selected\n");
2131    return;
2132  }
2133
2134  /* for now we skip admin messages. */
2135  if (owl_message_is_type_admin(m)
2136      || owl_message_is_login(m)
2137      || !owl_message_is_type_zephyr(m)) {
2138    owl_function_makemsg("smartzpunt doesn't support this message type.");
2139    return;
2140  }
2141
2142  mclass = owl_message_get_class(m);
2143  minst = owl_message_get_instance(m);
2144  if (!mclass || !*mclass || *mclass==' '
2145      || (!strcasecmp(mclass, "message") && !strcasecmp(minst, "personal"))
2146      || (type && (!minst || !*minst|| *minst==' '))) {
2147    owl_function_makemsg("smartzpunt can't safely do this for <%s,%s>",
2148                         mclass, minst);
2149  } else {
2150    cmdprefix = "start-command zpunt ";
2151    cmd = owl_malloc(strlen(cmdprefix)+strlen(mclass)+strlen(minst)+3);
2152    strcpy(cmd, cmdprefix);
2153    strcat(cmd, mclass);
2154    if (type) {
2155      strcat(cmd, " ");
2156      strcat(cmd, minst);
2157    } else {
2158      strcat(cmd, " *");
2159    }
2160    owl_function_command(cmd);
2161    owl_free(cmd);
2162  }
2163}
2164
2165
2166
2167void owl_function_color_current_filter(char *color) {
2168  owl_filter *f;
2169  char *name;
2170
2171  name=owl_view_get_filtname(owl_global_get_current_view(&g));
2172  f=owl_global_get_filter(&g, name);
2173  if (!f) {
2174    owl_function_makemsg("Unknown filter");
2175    return;
2176  }
2177
2178  /* don't touch the all filter */
2179  if (!strcmp(name, "all")) {
2180    owl_function_makemsg("You may not change the 'all' filter.");
2181    return;
2182  }
2183
2184  /* deal with the case of trying change the filter color */
2185  owl_filter_set_color(f, owl_util_string_to_color(color));
2186  owl_global_set_needrefresh(&g);
2187  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2188}
2189
2190void owl_function_show_colors() {
2191  owl_fmtext fm;
2192
2193  owl_fmtext_init_null(&fm);
2194  owl_fmtext_append_normal_color(&fm, "default\n", OWL_COLOR_DEFAULT);
2195  owl_fmtext_append_normal_color(&fm, "red\n", OWL_COLOR_RED);
2196  owl_fmtext_append_normal_color(&fm, "green\n", OWL_COLOR_GREEN);
2197  owl_fmtext_append_normal_color(&fm, "yellow\n", OWL_COLOR_YELLOW);
2198  owl_fmtext_append_normal_color(&fm, "blue\n", OWL_COLOR_BLUE);
2199  owl_fmtext_append_normal_color(&fm, "magenta\n", OWL_COLOR_MAGENTA);
2200  owl_fmtext_append_normal_color(&fm, "cyan\n", OWL_COLOR_CYAN);
2201  owl_fmtext_append_normal_color(&fm, "white\n", OWL_COLOR_WHITE);
2202
2203  owl_function_popless_fmtext(&fm);
2204  owl_fmtext_free(&fm);
2205}
2206
2207void owl_function_zpunt(char *class, char *inst, char *recip, int direction) {
2208  /* add the given class, inst, recip to the punt list for filtering.
2209   *   if direction==0 then punt
2210   *   if direction==1 then unpunt */
2211  owl_filter *f;
2212  owl_list *fl;
2213  char *buff;
2214  int ret, i, j;
2215
2216  fl=owl_global_get_puntlist(&g);
2217
2218  /* first, create the filter */
2219  f=malloc(sizeof(owl_filter));
2220  buff=malloc(strlen(class)+strlen(inst)+strlen(recip)+100);
2221  if (!strcmp(recip, "*")) {
2222    sprintf(buff, "class ^%s$ and instance ^%s$", class, inst);
2223  } else {
2224    sprintf(buff, "class ^%s$ and instance ^%s$ and recipient %s", class, inst, recip);
2225  }
2226  owl_function_debugmsg("About to filter %s", buff);
2227  ret=owl_filter_init_fromstring(f, "punt-filter", buff);
2228  owl_free(buff);
2229  if (ret) {
2230    owl_function_makemsg("Error creating filter for zpunt");
2231    owl_filter_free(f);
2232    return;
2233  }
2234
2235  /* Check for an identical filter */
2236  j=owl_list_get_size(fl);
2237  for (i=0; i<j; i++) {
2238    if (owl_filter_equiv(f, owl_list_get_element(fl, i))) {
2239      /* if we're punting, then just silently bow out on this duplicate */
2240      if (direction==0) {
2241        owl_filter_free(f);
2242        return;
2243      }
2244
2245      /* if we're unpunting, then remove this filter from the puntlist */
2246      if (direction==1) {
2247        owl_filter_free(owl_list_get_element(fl, i));
2248        owl_list_remove_element(fl, i);
2249        return;
2250      }
2251    }
2252  }
2253
2254  /* If we're punting, add the filter to the global punt list */
2255  if (direction==0) {
2256    owl_list_append_element(fl, f);
2257  }
2258}
2259
2260void owl_function_activate_keymap(char *keymap) {
2261  if (!owl_keyhandler_activate(owl_global_get_keyhandler(&g), keymap)) {
2262    owl_function_makemsg("Unable to activate keymap '%s'", keymap);
2263  }
2264}
2265
2266
2267void owl_function_show_keymaps() {
2268  owl_list l;
2269  owl_fmtext fm;
2270  owl_keymap *km;
2271  owl_keyhandler *kh;
2272  int i, numkm;
2273  char *kmname;
2274
2275  kh = owl_global_get_keyhandler(&g);
2276  owl_fmtext_init_null(&fm);
2277  owl_fmtext_append_bold(&fm, "Keymaps:   ");
2278  owl_fmtext_append_normal(&fm, "(use 'show keymap <name>' for details)\n");
2279  owl_keyhandler_get_keymap_names(kh, &l);
2280  owl_fmtext_append_list(&fm, &l, "\n", owl_function_keymap_summary);
2281  owl_fmtext_append_normal(&fm, "\n");
2282
2283  numkm = owl_list_get_size(&l);
2284  for (i=0; i<numkm; i++) {
2285    kmname = owl_list_get_element(&l, i);
2286    km = owl_keyhandler_get_keymap(kh, kmname);
2287    owl_fmtext_append_bold(&fm, "\n\n----------------------------------------------------------------------------------------------------\n\n");
2288    owl_keymap_get_details(km, &fm);   
2289  }
2290  owl_fmtext_append_normal(&fm, "\n");
2291 
2292  owl_function_popless_fmtext(&fm);
2293  owl_keyhandler_keymap_namelist_free(&l);
2294  owl_fmtext_free(&fm);
2295}
2296
2297char *owl_function_keymap_summary(void *name) {
2298  owl_keymap *km
2299    = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
2300  if (km) return owl_keymap_summary(km);
2301  else return(NULL);
2302}
2303
2304/* TODO: implement for real */
2305void owl_function_show_keymap(char *name) {
2306  owl_fmtext fm;
2307  owl_keymap *km;
2308
2309  owl_fmtext_init_null(&fm);
2310  km = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
2311  if (km) {
2312    owl_keymap_get_details(km, &fm);
2313  } else {
2314    owl_fmtext_append_normal(&fm, "No such keymap...\n");
2315  } 
2316  owl_function_popless_fmtext(&fm);
2317  owl_fmtext_free(&fm);
2318}
2319
2320void owl_function_help_for_command(char *cmdname) {
2321  owl_fmtext fm;
2322
2323  owl_fmtext_init_null(&fm);
2324  owl_cmd_get_help(owl_global_get_cmddict(&g), cmdname, &fm);
2325  owl_function_popless_fmtext(&fm); 
2326  owl_fmtext_free(&fm);
2327}
2328
2329void owl_function_search_start(char *string, int direction) {
2330  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
2331  owl_global_set_search_active(&g, string);
2332  owl_function_search_helper(0, direction);
2333}
2334
2335void owl_function_search_continue(int direction) {
2336  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
2337  owl_function_search_helper(1, direction);
2338}
2339
2340void owl_function_search_helper(int mode, int direction) {
2341  /* move to a message that contains the string.  If direction is
2342   * OWL_DIRECTION_DOWNWARDS then search fowards, if direction is
2343   * OWL_DIRECTION_UPWARDS then search backwards.
2344   *
2345   * If mode==0 then it will stay on the current message if it
2346   * contains the string.
2347   */
2348
2349  owl_view *v;
2350  int viewsize, i, curmsg, start;
2351  owl_message *m;
2352
2353  v=owl_global_get_current_view(&g);
2354  viewsize=owl_view_get_size(v);
2355  curmsg=owl_global_get_curmsg(&g);
2356 
2357  if (viewsize==0) {
2358    owl_function_makemsg("No messages present");
2359    return;
2360  }
2361
2362  if (mode==0) {
2363    start=curmsg;
2364  } else if (direction==OWL_DIRECTION_DOWNWARDS) {
2365    start=curmsg+1;
2366  } else {
2367    start=curmsg-1;
2368  }
2369
2370  /* bounds check */
2371  if (start>=viewsize || start<0) {
2372    owl_function_makemsg("No further matches found");
2373    return;
2374  }
2375
2376  for (i=start; i<viewsize && i>=0;) {
2377    m=owl_view_get_element(v, i);
2378    if (owl_message_search(m, owl_global_get_search_string(&g))) {
2379      owl_global_set_curmsg(&g, i);
2380      owl_function_calculate_topmsg(direction);
2381      owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2382      if (direction==OWL_DIRECTION_DOWNWARDS) {
2383        owl_global_set_direction_downwards(&g);
2384      } else {
2385        owl_global_set_direction_upwards(&g);
2386      }
2387      return;
2388    }
2389    if (direction==OWL_DIRECTION_DOWNWARDS) {
2390      i++;
2391    } else {
2392      i--;
2393    }
2394  }
2395  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2396  owl_function_makemsg("No matches found");
2397}
2398
2399
2400/* strips formatting from ztext and returns the unformatted text.
2401 * caller is responsible for freeing. */
2402char *owl_function_ztext_stylestrip(char *zt) {
2403  owl_fmtext fm;
2404  char *plaintext;
2405
2406  owl_fmtext_init_null(&fm);
2407  owl_fmtext_append_ztext(&fm, zt);
2408  plaintext = owl_fmtext_print_plain(&fm);
2409  owl_fmtext_free(&fm);
2410  return(plaintext);
2411}
2412
2413/* popup a znol listing.  If file is NULL use the default .anyone */
2414/* this doesn't obey 'elapsed' or 'timesort' yet */
2415void owl_function_zlist(char *file, int elapsed, int timesort) {
2416  char *ourfile, *tmp, buff[LINE], *line;
2417  FILE *f;
2418  int numlocs, ret, i;
2419  ZLocations_t location[200];
2420  owl_fmtext fm;
2421
2422  if (file==NULL) {
2423    tmp=owl_global_get_homedir(&g);
2424    if (!tmp) {
2425      owl_function_makemsg("Could not determine home directory");
2426      return;
2427    }
2428    ourfile=owl_malloc(strlen(tmp)+50);
2429    sprintf(ourfile, "%s/.anyone", owl_global_get_homedir(&g));
2430  } else {
2431    ourfile=owl_strdup(file);
2432  }
2433
2434  f=fopen(ourfile, "r");
2435  if (!f) {
2436    owl_function_makemsg("Error opening file %s", ourfile);
2437    return;
2438  }
2439
2440  owl_fmtext_init_null(&fm);
2441   
2442  while (fgets(buff, LINE, f)!=NULL) {
2443    /* ignore comments, blank lines etc. */
2444    if (buff[0]=='#') continue;
2445    if (buff[0]=='\n') continue;
2446    if (buff[0]=='\0') continue;
2447
2448    /* strip the \n */
2449    buff[strlen(buff)-1]='\0';
2450
2451    /* ingore from # on */
2452    tmp=strchr(buff, '#');
2453    if (tmp) tmp[0]='\0';
2454
2455    /* ingore from SPC */
2456    tmp=strchr(buff, ' ');
2457    if (tmp) tmp[0]='\0';
2458
2459    /* stick on the local realm. */
2460    if (!strchr(buff, '@')) {
2461      strcat(buff, "@");
2462      strcat(buff, ZGetRealm());
2463    }
2464
2465    ret=ZLocateUser(buff, &numlocs, ZAUTH);
2466    if (ret!=ZERR_NONE) {
2467      owl_function_makemsg("Error getting location for %s", buff);
2468      continue;
2469    }
2470
2471    numlocs=200;
2472    ret=ZGetLocations(location, &numlocs);
2473    if (ret==0) {
2474      for (i=0; i<numlocs; i++) {
2475        line=malloc(strlen(location[i].host)+strlen(location[i].time)+strlen(location[i].tty)+100);
2476        tmp=short_zuser(buff);
2477        sprintf(line, "%-10.10s %-24.24s %-12.12s  %20.20s\n",
2478                tmp,
2479                location[i].host,
2480                location[i].tty,
2481                location[i].time);
2482        owl_fmtext_append_normal(&fm, line);
2483        owl_free(tmp);
2484      }
2485      if (numlocs>=200) {
2486        owl_fmtext_append_normal(&fm, "Too many locations found for this user, truncating.\n");
2487      }
2488    }
2489  }
2490  fclose(f);
2491
2492  owl_function_popless_fmtext(&fm);
2493  owl_fmtext_free(&fm);
2494
2495  owl_free(ourfile);
2496}
2497
2498void owl_function_dump(char *filename) {
2499  int i, j, count;
2500  owl_message *m;
2501  owl_view *v;
2502  FILE *file;
2503  /* struct stat sbuf; */
2504
2505  v=owl_global_get_current_view(&g);
2506
2507  /* in the future make it ask yes/no */
2508  /*
2509  ret=stat(filename, &sbuf);
2510  if (!ret) {
2511    ret=owl_function_askyesno("File exists, continue? [Y/n]");
2512    if (!ret) return;
2513  }
2514  */
2515
2516  file=fopen(filename, "w");
2517  if (!file) {
2518    owl_function_makemsg("Error opening file");
2519    return;
2520  }
2521
2522  count=0;
2523  j=owl_view_get_size(v);
2524  for (i=0; i<j; i++) {
2525    m=owl_view_get_element(v, i);
2526    fputs(owl_message_get_text(m), file);
2527  }
2528  fclose(file);
2529}
Note: See TracBrowser for help on using the repository browser.