source: functions.c @ 601a9e0

barnowl_perlaimdebianowlrelease-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 601a9e0 was 601a9e0, checked in by James M. Kretchmar <kretch@mit.edu>, 21 years ago
Patch to fix memory bug in replying to CC messages If we're on Athena and have static krb (or other) libraries, use them Added "athstatic" program to the release, which handles the above Cast to an int for isspace, to make gcc -Wall quiet Added 'zlist' and 'l' to basic help.
  • Property mode set to 100644
File size: 66.2 KB
Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <signal.h>
5#include <string.h>
6#include <com_err.h>
7#include <time.h>
8#include "owl.h"
9
10static const char fileIdent[] = "$Id$";
11
12void owl_function_noop(void) {
13  return;
14}
15
16char *owl_function_command(char *cmdbuff) {
17  owl_function_debugmsg("executing command: %s", cmdbuff);
18  return owl_cmddict_execute(owl_global_get_cmddict(&g), 
19                             owl_global_get_context(&g), cmdbuff);
20}
21
22void owl_function_command_norv(char *cmdbuff) {
23  char *rv;
24  rv=owl_function_command(cmdbuff);
25  if (rv) owl_free(rv);
26}
27
28void owl_function_command_alias(char *alias_from, char *alias_to) {
29  owl_cmddict_add_alias(owl_global_get_cmddict(&g), alias_from, alias_to);
30}
31
32owl_cmd *owl_function_get_cmd(char *name) {
33  return owl_cmddict_find(owl_global_get_cmddict(&g), name);
34}
35
36void owl_function_show_commands() {
37  owl_list l;
38  owl_fmtext fm;
39
40  owl_fmtext_init_null(&fm);
41  owl_fmtext_append_bold(&fm, "Commands:  ");
42  owl_fmtext_append_normal(&fm, "(use 'show command <name>' for details)\n");
43  owl_cmddict_get_names(owl_global_get_cmddict(&g), &l);
44  owl_fmtext_append_list(&fm, &l, "\n", owl_function_cmd_describe);
45  owl_fmtext_append_normal(&fm, "\n");
46  owl_function_popless_fmtext(&fm);
47  owl_cmddict_namelist_free(&l);
48  owl_fmtext_free(&fm);
49}
50
51char *owl_function_cmd_describe(void *name) {
52  owl_cmd *cmd = owl_cmddict_find(owl_global_get_cmddict(&g), name);
53  if (cmd) return owl_cmd_describe(cmd);
54  else return(NULL);
55}
56
57void owl_function_show_command(char *name) {
58  owl_function_help_for_command(name);
59}
60
61void owl_function_adminmsg(char *header, char *body) {
62  owl_message *m;
63  int followlast;
64
65  followlast=owl_global_should_followlast(&g);
66  m=owl_malloc(sizeof(owl_message));
67  owl_message_create_admin(m, header, body);
68  owl_messagelist_append_element(owl_global_get_msglist(&g), m);
69  owl_view_consider_message(owl_global_get_current_view(&g), m);
70
71  if (followlast) owl_function_lastmsg_noredisplay();
72
73  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
74  if (owl_popwin_is_active(owl_global_get_popwin(&g))) {
75    owl_popwin_refresh(owl_global_get_popwin(&g));
76  }
77 
78  wnoutrefresh(owl_global_get_curs_recwin(&g));
79  owl_global_set_needrefresh(&g);
80}
81
82void owl_function_make_outgoing_zephyr(char *header, char *body, char *zwriteline, char *zsig) {
83  owl_message *m;
84  int followlast;
85  owl_zwrite z;
86  char *tobuff, *recip;
87 
88  followlast=owl_global_should_followlast(&g);
89
90  /* create a zwrite for the purpose of filling in other message fields */
91  owl_zwrite_create_from_line(&z, zwriteline);
92
93  /* in 'tobuff' place the "Message sent to foo" string.
94   * Right now this only works for one recipient */
95  tobuff=owl_malloc(strlen(owl_zwrite_get_recip_n(&z, 0))+100);
96  sprintf(tobuff, "Zephyr sent to %s  (Zsig: %s)", owl_zwrite_get_recip_n(&z, 0), zsig);
97
98  /* create the message */
99  m=owl_malloc(sizeof(owl_message));
100  owl_message_create(m,  tobuff, body);
101  owl_message_set_direction_out(m);
102  owl_message_set_type_zephyr(m);
103
104  /* set zwriteline */
105  owl_message_set_zwriteline(m, zwriteline);
106
107  owl_message_set_class(m, owl_zwrite_get_class(&z));
108  owl_message_set_instance(m, owl_zwrite_get_instance(&z));
109  owl_message_set_opcode(m, owl_zwrite_get_opcode(&z));
110  owl_message_set_realm(m, owl_zwrite_get_realm(&z));
111  owl_message_set_sender(m, ZGetSender());
112  /* this only gets the first recipient for now, must fix */
113  recip=long_zuser(owl_zwrite_get_recip_n(&z, 0));
114  owl_message_set_recipient(m, recip);
115  owl_free(recip);
116
117  /* add it to the global list */
118  owl_messagelist_append_element(owl_global_get_msglist(&g), m);
119  owl_view_consider_message(owl_global_get_current_view(&g), m);
120
121  if (followlast) owl_function_lastmsg_noredisplay();
122
123  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
124  if (owl_popwin_is_active(owl_global_get_popwin(&g))) {
125    owl_popwin_refresh(owl_global_get_popwin(&g));
126  }
127 
128  wnoutrefresh(owl_global_get_curs_recwin(&g));
129  owl_global_set_needrefresh(&g);
130  owl_free(tobuff);
131  owl_zwrite_free(&z);
132}
133
134void owl_function_zwrite_setup(char *line) {
135  owl_editwin *e;
136  char buff[1024];
137  owl_zwrite z;
138  int ret;
139
140  /* check the arguments */
141  ret=owl_zwrite_create_from_line(&z, line);
142  if (ret) {
143    owl_function_makemsg("Error in zwrite arugments");
144    owl_zwrite_free(&z);
145    return;
146  }
147
148  /* send a ping if necessary */
149  if (owl_global_is_txping(&g)) {
150    owl_zwrite_send_ping(&z);
151  }
152  owl_zwrite_free(&z);
153
154  /* create and setup the editwin */
155  e=owl_global_get_typwin(&g);
156  owl_editwin_new_style(e, OWL_EDITWIN_STYLE_MULTILINE, owl_global_get_msg_history(&g));
157
158  if (!owl_global_get_lockout_ctrld(&g)) {
159    owl_function_makemsg("Type your zephyr below.  End with ^D or a dot on a line by itself.  ^C will quit.");
160  } else {
161    owl_function_makemsg("Type your zephyr below.  End with a dot on a line by itself.  ^C will quit.");
162  }
163
164  owl_editwin_clear(e);
165  owl_editwin_set_dotsend(e);
166  strcpy(buff, "----> ");
167  strcat(buff, line);
168  strcat(buff, "\n");
169  owl_editwin_set_locktext(e, buff);
170
171  /* make it active */
172  owl_global_set_typwin_active(&g);
173}
174
175void owl_function_zwrite(char *line) {
176  char *tmpbuff, buff[1024];
177  owl_zwrite z;
178  int i, j;
179
180  /* create the zwrite and send the message */
181  owl_zwrite_create_from_line(&z, line);
182  owl_zwrite_send_message(&z, owl_editwin_get_text(owl_global_get_typwin(&g)));
183  owl_function_makemsg("Waiting for ack...");
184
185  /* display the message as an outgoing message in the receive window */
186  if (owl_global_is_displayoutgoing(&g) && owl_zwrite_is_personal(&z)) {
187    owl_zwrite_get_recipstr(&z, buff);
188    tmpbuff = owl_sprintf("Message sent to %s", buff);
189    owl_function_make_outgoing_zephyr(tmpbuff, owl_editwin_get_text(owl_global_get_typwin(&g)), line, owl_zwrite_get_zsig(&z));
190    owl_free(tmpbuff);
191  }
192
193  /* log it if we have logging turned on */
194  if (owl_global_is_logging(&g) && owl_zwrite_is_personal(&z)) {
195    j=owl_zwrite_get_numrecips(&z);
196    for (i=0; i<j; i++) {
197      owl_log_outgoing(owl_zwrite_get_recip_n(&z, i),
198                       owl_editwin_get_text(owl_global_get_typwin(&g)));
199    }
200  }
201
202  /* free the zwrite */
203  owl_zwrite_free(&z);
204}
205
206
207/* If filter is non-null, looks for the next message matching
208 * that filter.  If skip_deleted, skips any deleted messages.
209 * If last_if_none, will stop at the last message in the view
210 * if no matching messages are found.  */
211void owl_function_nextmsg_full(char *filter, int skip_deleted, int last_if_none) {
212  int curmsg, i, viewsize, found;
213  owl_view *v;
214  owl_filter *f = NULL;
215  owl_message *m;
216
217  v=owl_global_get_current_view(&g);
218
219  if (filter) {
220    f=owl_global_get_filter(&g, filter);
221    if (!f) {
222      owl_function_makemsg("No %s filter defined", filter);
223      return;
224    }
225  }
226
227  curmsg=owl_global_get_curmsg(&g);
228  viewsize=owl_view_get_size(v);
229  found=0;
230
231  /* just check to make sure we're in bounds... */
232  if (curmsg>viewsize-1) curmsg=viewsize-1;
233  if (curmsg<0) curmsg=0;
234
235  for (i=curmsg+1; i<viewsize; i++) {
236    m=owl_view_get_element(v, i);
237    if (skip_deleted && owl_message_is_delete(m)) continue;
238    if (f && !owl_filter_message_match(f, m)) continue;
239    found = 1;
240    break;
241  }
242
243  if (i>owl_view_get_size(v)-1) i=owl_view_get_size(v)-1;
244
245  if (!found) {
246    owl_function_makemsg("already at last%s message%s%s",
247                         skip_deleted?" non-deleted":"",
248                         filter?" in ":"", filter?filter:"");
249    /* if (!skip_deleted) owl_function_beep(); */
250  }
251
252  if (last_if_none || found) {
253    owl_global_set_curmsg(&g, i);
254    owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
255    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
256    owl_global_set_direction_downwards(&g);
257  }
258}
259
260void owl_function_prevmsg_full(char *filter, int skip_deleted, int first_if_none) {
261  int curmsg, i, viewsize, found;
262  owl_view *v;
263  owl_filter *f = NULL;
264  owl_message *m;
265
266  v=owl_global_get_current_view(&g);
267
268  if (filter) {
269    f=owl_global_get_filter(&g, filter);
270    if (!f) {
271      owl_function_makemsg("No %s filter defined", filter);
272      return;
273    }
274  }
275
276  curmsg=owl_global_get_curmsg(&g);
277  viewsize=owl_view_get_size(v);
278  found=0;
279
280  /* just check to make sure we're in bounds... */
281  if (curmsg<0) curmsg=0;
282
283  for (i=curmsg-1; i>=0; i--) {
284    m=owl_view_get_element(v, i);
285    if (skip_deleted && owl_message_is_delete(m)) continue;
286    if (f && !owl_filter_message_match(f, m)) continue;
287    found = 1;
288    break;
289  }
290
291  if (i<0) i=0;
292
293  if (!found) {
294    owl_function_makemsg("already at first%s message%s%s",
295                         skip_deleted?" non-deleted":"",
296                         filter?" in ":"", filter?filter:"");
297    /* if (!skip_deleted) owl_function_beep(); */
298  }
299
300  if (first_if_none || found) {
301    owl_global_set_curmsg(&g, i);
302    owl_function_calculate_topmsg(OWL_DIRECTION_UPWARDS);
303    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
304    owl_global_set_direction_upwards(&g);
305  }
306}
307
308void owl_function_nextmsg() {
309  owl_function_nextmsg_full(NULL, 0, 1);
310}
311
312
313void owl_function_prevmsg() {
314  owl_function_prevmsg_full(NULL, 0, 1);
315}
316
317void owl_function_nextmsg_notdeleted() {
318  owl_function_nextmsg_full(NULL, 1, 1);
319}
320
321void owl_function_prevmsg_notdeleted() {
322  owl_function_prevmsg_full(NULL, 1, 1);
323}
324
325
326void owl_function_nextmsg_personal() {
327  owl_function_nextmsg_full("personal", 0, 0);
328}
329
330void owl_function_prevmsg_personal() {
331  owl_function_prevmsg_full("personal", 0, 0);
332}
333
334
335/* if move_after is 1, moves after the delete */
336void owl_function_deletecur(int move_after) {
337  int curmsg;
338  owl_view *v;
339
340  v=owl_global_get_current_view(&g);
341
342  /* bail if there's no current message */
343  if (owl_view_get_size(v) < 1) {
344    owl_function_makemsg("No current message to delete");
345    return;
346  }
347
348  /* mark the message for deletion */
349  curmsg=owl_global_get_curmsg(&g);
350  owl_view_delete_element(v, curmsg);
351
352  if (move_after) {
353    /* move the poiner in the appropriate direction
354     * to the next undeleted msg */
355    if (owl_global_get_direction(&g)==OWL_DIRECTION_UPWARDS) {
356      owl_function_prevmsg_notdeleted();
357    } else {
358      owl_function_nextmsg_notdeleted();
359    }
360  }
361}
362
363
364void owl_function_undeletecur(int move_after) {
365  int curmsg;
366  owl_view *v;
367
368  v=owl_global_get_current_view(&g);
369 
370  if (owl_view_get_size(v) < 1) {
371    owl_function_makemsg("No current message to undelete");
372    return;
373  }
374  curmsg=owl_global_get_curmsg(&g);
375
376  owl_view_undelete_element(v, curmsg);
377
378  if (move_after) {
379    if (owl_global_get_direction(&g)==OWL_DIRECTION_UPWARDS) {
380      if (curmsg>0) {
381        owl_function_prevmsg();
382      } else {
383        owl_function_nextmsg();
384      }
385    } else {
386      owl_function_nextmsg();
387    }
388  }
389
390  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
391}
392
393
394void owl_function_expunge() {
395  int curmsg;
396  owl_message *m;
397  owl_messagelist *ml;
398  owl_view *v;
399  int i, j;
400
401  curmsg=owl_global_get_curmsg(&g);
402  v=owl_global_get_current_view(&g);
403  ml=owl_global_get_msglist(&g);
404
405  /* just check to make sure we're in bounds... */
406  if (curmsg>owl_view_get_size(v)-1) curmsg=owl_view_get_size(v)-1;
407  if (curmsg<0) curmsg=0;
408
409  /* first try to move to an undeleted message in the view */
410  m=owl_view_get_element(v, curmsg);
411  if (owl_message_is_delete(m)) {
412    /* try to find the next undeleted message */
413    j=owl_view_get_size(v);
414    for (i=curmsg+1; i<j; i++) {
415      if (!owl_message_is_delete(owl_view_get_element(v, i))) {
416        owl_global_set_curmsg(&g, i);
417        break;
418      }
419    }
420
421    /* if we weren't successful try to find one backwards */
422    curmsg=owl_global_get_curmsg(&g);
423    if (owl_message_is_delete(owl_view_get_element(v, curmsg))) {
424      for (i=curmsg; i>0; i--) {
425        if (!owl_message_is_delete(owl_view_get_element(v, i))) {
426          owl_global_set_curmsg(&g, i);
427          break;
428        }
429      }
430    }
431  }
432
433  /* expunge the message list */
434  owl_messagelist_expunge(ml);
435
436  /* update all views (we only have one right now) */
437  owl_view_recalculate(v);
438
439  if (curmsg>owl_view_get_size(v)-1) {
440    owl_global_set_curmsg(&g, owl_view_get_size(v)-1);
441    if (owl_global_get_curmsg(&g)<0) {
442      owl_global_set_curmsg(&g, 0);
443    }
444    owl_function_calculate_topmsg(OWL_DIRECTION_NONE);
445  }
446
447  /* if there are no messages set the direction to down in case we
448     delete everything upwards */
449  owl_global_set_direction_downwards(&g);
450 
451  owl_function_makemsg("Messages expunged");
452  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
453}
454
455
456void owl_function_firstmsg() {
457  owl_global_set_curmsg(&g, 0);
458  owl_global_set_topmsg(&g, 0);
459  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
460  owl_global_set_direction_downwards(&g);
461}
462
463void owl_function_lastmsg_noredisplay() {
464  int oldcurmsg, curmsg;
465  owl_view *v;
466
467  v=owl_global_get_current_view(&g);
468  oldcurmsg=owl_global_get_curmsg(&g);
469  curmsg=owl_view_get_size(v)-1; 
470  if (curmsg<0) curmsg=0;
471  owl_global_set_curmsg(&g, curmsg);
472  if (oldcurmsg < curmsg) {
473    owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
474  } else if (curmsg<owl_view_get_size(v)) {
475    /* If already at the end, blank the screen and move curmsg
476     * past the end of the messages. */
477    owl_global_set_topmsg(&g, curmsg+1);
478    owl_global_set_curmsg(&g, curmsg+1);
479  } 
480  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
481  owl_global_set_direction_downwards(&g);
482}
483
484void owl_function_lastmsg() {
485  owl_function_lastmsg_noredisplay();
486  owl_mainwin_redisplay(owl_global_get_mainwin(&g)); 
487}
488
489void owl_function_shift_right() {
490  owl_global_set_rightshift(&g, owl_global_get_rightshift(&g)+10);
491  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
492  owl_global_set_needrefresh(&g);
493}
494
495
496void owl_function_shift_left() {
497  int shift;
498
499  shift=owl_global_get_rightshift(&g);
500  if (shift>=10) {
501    owl_global_set_rightshift(&g, shift-10);
502    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
503    owl_global_set_needrefresh(&g);
504  } else {
505    owl_function_beep();
506    owl_function_makemsg("Already full left");
507  }
508}
509
510
511void owl_function_unsuball() {
512  unsuball();
513  owl_function_makemsg("Unsubscribed from all messages.");
514}
515
516void owl_function_loadsubs(char *file) {
517  int ret;
518  ret=owl_zephyr_loadsubs(file);
519  if (ret==0) {
520    owl_function_makemsg("Subscribed to messages from file.");
521  } else if (ret==-1) {
522    owl_function_makemsg("Could not open file.");
523  } else {
524    owl_function_makemsg("Error subscribing to messages from file.");
525  }
526}
527
528void owl_function_suspend() {
529  endwin();
530  printf("\n");
531  kill(getpid(), SIGSTOP);
532
533  /* resize to reinitialize all the windows when we come back */
534  owl_command_resize();
535}
536
537void owl_function_zaway_toggle() {
538  if (!owl_global_is_zaway(&g)) {
539    owl_global_set_zaway_msg(&g, owl_global_get_zaway_msg_default(&g));
540    owl_function_zaway_on();
541  } else {
542    owl_function_zaway_off();
543  }
544}
545
546void owl_function_zaway_on() {
547  owl_global_set_zaway_on(&g);
548  owl_function_makemsg("zaway set (%s)", owl_global_get_zaway_msg(&g));
549}
550
551void owl_function_zaway_off() {
552  owl_global_set_zaway_off(&g);
553  owl_function_makemsg("zaway off");
554}
555
556void owl_function_quit() {
557  char *ret;
558 
559  /* zlog out if we need to */
560  if (owl_global_is_shutdownlogout(&g)) {
561    owl_function_zlog_out();
562  }
563
564  /* execute the commands in shutdown */
565  ret = owl_config_execute("owl::shutdown();");
566  if (ret) owl_free(ret);
567
568  /* final clean up */
569  unsuball();
570  ZClosePort();
571  endwin();
572  owl_function_debugmsg("Quitting Owl");
573  exit(0);
574}
575
576
577void owl_function_zlog_in() {
578  char *exposure, *eset;
579  int ret;
580
581  eset=EXPOSE_REALMVIS;
582  exposure=ZGetVariable("exposure");
583  if (exposure==NULL) {
584    eset=EXPOSE_REALMVIS;
585  } else if (!strcasecmp(exposure,EXPOSE_NONE)) {
586    eset = EXPOSE_NONE;
587  } else if (!strcasecmp(exposure,EXPOSE_OPSTAFF)) {
588    eset = EXPOSE_OPSTAFF;
589  } else if (!strcasecmp(exposure,EXPOSE_REALMVIS)) {
590    eset = EXPOSE_REALMVIS;
591  } else if (!strcasecmp(exposure,EXPOSE_REALMANN)) {
592    eset = EXPOSE_REALMANN;
593  } else if (!strcasecmp(exposure,EXPOSE_NETVIS)) {
594    eset = EXPOSE_NETVIS;
595  } else if (!strcasecmp(exposure,EXPOSE_NETANN)) {
596    eset = EXPOSE_NETANN;
597  }
598   
599  ret=ZSetLocation(eset);
600  if (ret != ZERR_NONE) {
601    /*
602      char buff[LINE];
603      sprintf(buff, "Error setting location: %s", error_message(ret));
604      owl_function_makemsg(buff);
605    */
606  }
607}
608
609void owl_function_zlog_out() {
610  int ret;
611 
612  ret=ZUnsetLocation();
613  if (ret != ZERR_NONE) {
614    /*
615      char buff[LINE];
616      sprintf(buff, "Error unsetting location: %s", error_message(ret));
617      owl_function_makemsg(buff);
618    */
619  }
620}
621
622
623void owl_function_makemsg(char *fmt, ...) {
624  va_list ap;
625  char buff[2048];
626
627  va_start(ap, fmt);
628  werase(owl_global_get_curs_msgwin(&g));
629 
630  vsnprintf(buff, 2048, fmt, ap);
631  owl_function_debugmsg("makemsg: %s", buff);
632  waddstr(owl_global_get_curs_msgwin(&g), buff); 
633  wnoutrefresh(owl_global_get_curs_msgwin(&g));
634  owl_global_set_needrefresh(&g);
635  va_end(ap);
636}
637
638void owl_function_errormsg(char *fmt, ...) {
639  va_list ap;
640  char buff[2048];
641
642  va_start(ap, fmt);
643  werase(owl_global_get_curs_msgwin(&g));
644 
645  vsnprintf(buff, 2048, fmt, ap);
646  owl_function_debugmsg("ERROR: %s", buff);
647  waddstr(owl_global_get_curs_msgwin(&g), buff); 
648  waddstr(owl_global_get_curs_msgwin(&g), "ERROR: "); 
649  wnoutrefresh(owl_global_get_curs_msgwin(&g));
650  owl_global_set_needrefresh(&g);
651  va_end(ap);
652}
653
654
655void owl_function_openurl() {
656  /* visit the first url in the current message */
657  owl_message *m;
658  owl_view *v;
659  char *ptr1, *ptr2, *text, url[LINE], tmpbuff[LINE];
660  int webbrowser;
661
662  webbrowser = owl_global_get_webbrowser(&g);
663
664  if (webbrowser < 0 || webbrowser == OWL_WEBBROWSER_NONE) {
665    owl_function_makemsg("No browser selected");
666    return;
667  }
668
669  v=owl_global_get_current_view(&g);
670 
671  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
672
673  if (!m || owl_view_get_size(v)==0) {
674    owl_function_makemsg("No current message selected");
675    return;
676  }
677
678  text=owl_message_get_text(m);
679
680  /* First look for a good URL */ 
681  if ((ptr1=strstr(text, "http://"))!=NULL) {
682    ptr2=strpbrk(ptr1, " \n\t");
683    if (ptr2) {
684      strncpy(url, ptr1, ptr2-ptr1+1);
685      url[ptr2-ptr1+1]='\0';
686    } else {
687      strcpy(url, ptr1);
688    }
689
690    /* if we had <http strip a trailing > */
691    if (ptr1>text && ptr1[-1]=='<') {
692      if (url[strlen(url)-1]=='>') {
693        url[strlen(url)-1]='\0';
694      }
695    }
696  } else if ((ptr1=strstr(text, "https://"))!=NULL) {
697    /* Look for an https URL */ 
698    ptr2=strpbrk(ptr1, " \n\t");
699    if (ptr2) {
700      strncpy(url, ptr1, ptr2-ptr1+1);
701      url[ptr2-ptr1+1]='\0';
702    } else {
703      strcpy(url, ptr1);
704    }
705   
706    /* if we had <http strip a trailing > */
707    if (ptr1>text && ptr1[-1]=='<') {
708      if (url[strlen(url)-1]=='>') {
709        url[strlen(url)-1]='\0';
710      }
711    }
712  } else if ((ptr1=strstr(text, "www."))!=NULL) {
713    /* if we can't find a real url look for www.something */
714    ptr2=strpbrk(ptr1, " \n\t");
715    if (ptr2) {
716      strncpy(url, ptr1, ptr2-ptr1+1);
717      url[ptr2-ptr1+1]='\0';
718    } else {
719      strcpy(url, ptr1);
720    }
721  } else {
722    owl_function_beep();
723    owl_function_makemsg("Could not find URL to open.");
724    return;
725  }
726
727  /* Make sure there aren't any quotes or \'s in the url */
728  for (ptr1 = url; *ptr1; ptr1++) {
729    if (*ptr1 == '"' || *ptr1 == '\\') {
730      owl_function_beep();
731      owl_function_makemsg("URL contains invalid characters.");
732      return;
733    }
734  }
735 
736  /* NOTE: There are potentially serious security issues here... */
737
738  /* open the page */
739  owl_function_makemsg("Opening %s", url);
740  if (webbrowser == OWL_WEBBROWSER_NETSCAPE) {
741    snprintf(tmpbuff, LINE, "netscape -remote \"openURL(%s)\" > /dev/null 2> /dev/null", url);
742    system(tmpbuff); 
743  } else if (webbrowser == OWL_WEBBROWSER_GALEON) {
744    snprintf(tmpbuff, LINE, "galeon \"%s\" > /dev/null 2> /dev/null &", url);
745    system(tmpbuff); 
746  } else if (webbrowser == OWL_WEBBROWSER_OPERA) {
747    snprintf(tmpbuff, LINE, "opera \"%s\" > /dev/null 2> /dev/null &", url);
748    system(tmpbuff); 
749  }
750}
751
752void owl_function_calculate_topmsg(int direction) {
753  int recwinlines, topmsg, curmsg;
754  owl_view *v;
755
756  v=owl_global_get_current_view(&g);
757  curmsg=owl_global_get_curmsg(&g);
758  topmsg=owl_global_get_topmsg(&g);
759  recwinlines=owl_global_get_recwin_lines(&g);
760
761  /*
762  if (owl_view_get_size(v) < 1) {
763    return;
764  }
765  */
766
767  switch (owl_global_get_scrollmode(&g)) {
768  case OWL_SCROLLMODE_TOP:
769    topmsg = owl_function_calculate_topmsg_top(direction, v, curmsg, topmsg, recwinlines);
770    break;
771  case OWL_SCROLLMODE_NEARTOP:
772    topmsg = owl_function_calculate_topmsg_neartop(direction, v, curmsg, topmsg, recwinlines);
773    break;
774  case OWL_SCROLLMODE_CENTER:
775    topmsg = owl_function_calculate_topmsg_center(direction, v, curmsg, topmsg, recwinlines);
776    break;
777  case OWL_SCROLLMODE_PAGED:
778    topmsg = owl_function_calculate_topmsg_paged(direction, v, curmsg, topmsg, recwinlines, 0);
779    break;
780  case OWL_SCROLLMODE_PAGEDCENTER:
781    topmsg = owl_function_calculate_topmsg_paged(direction, v, curmsg, topmsg, recwinlines, 1);
782    break;
783  case OWL_SCROLLMODE_NORMAL:
784  default:
785    topmsg = owl_function_calculate_topmsg_normal(direction, v, curmsg, topmsg, recwinlines);
786  }
787  owl_function_debugmsg("Calculated a topmsg of %i", topmsg);
788  owl_global_set_topmsg(&g, topmsg);
789}
790
791/* Returns what the new topmsg should be. 
792 * Passed the last direction of movement,
793 * the current view,
794 * the current message number in the view,
795 * the top message currently being displayed,
796 * and the number of lines in the recwin.
797 */
798int owl_function_calculate_topmsg_top(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines) {
799  return(curmsg);
800}
801
802int owl_function_calculate_topmsg_neartop(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines) {
803  if (curmsg>0 
804      && (owl_message_get_numlines(owl_view_get_element(v, curmsg-1))
805          <  recwinlines/2)) {
806    return(curmsg-1);
807  } else {
808    return(curmsg);
809  }
810}
811 
812int owl_function_calculate_topmsg_center(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines) {
813  int i, last, lines;
814
815  last = curmsg;
816  lines = 0;
817  for (i=curmsg-1; i>=0; i--) {
818    lines += owl_message_get_numlines(owl_view_get_element(v, i));
819    if (lines > recwinlines/2) break;
820    last = i;
821  }
822  return(last);
823}
824 
825int owl_function_calculate_topmsg_paged(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines, int center_on_page) {
826  int i, last, lines, savey;
827 
828  /* If we're off the top of the screen, scroll up such that the
829   * curmsg is near the botton of the screen. */
830  if (curmsg < topmsg) {
831    last = curmsg;
832    lines = 0;
833    for (i=curmsg; i>=0; i--) {
834      lines += owl_message_get_numlines(owl_view_get_element(v, i));
835      if (lines > recwinlines) break;
836    last = i;
837    }
838    if (center_on_page) {
839      return(owl_function_calculate_topmsg_center(direction, v, curmsg, 0, recwinlines));
840    } else {
841      return(last);
842    }
843  }
844
845  /* Find number of lines from top to bottom of curmsg (store in savey) */
846  savey=0;
847  for (i=topmsg; i<=curmsg; i++) {
848    savey+=owl_message_get_numlines(owl_view_get_element(v, i));
849  }
850
851  /* if we're off the bottom of the screen, scroll down */
852  if (savey > recwinlines) {
853    if (center_on_page) {
854      return(owl_function_calculate_topmsg_center(direction, v, curmsg, 0, recwinlines));
855    } else {
856      return(curmsg);
857    }
858  }
859
860  /* else just stay as we are... */
861  return(topmsg);
862}
863
864
865int owl_function_calculate_topmsg_normal(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines) {
866  int savey, j, i, foo, y;
867
868  /* If we're off the top of the screen then center */
869  if (curmsg<topmsg) {
870    topmsg=owl_function_calculate_topmsg_center(direction, v, curmsg, 0, recwinlines);
871  }
872
873  /* Find number of lines from top to bottom of curmsg (store in savey) */
874  savey=0;
875  for (i=topmsg; i<=curmsg; i++) {
876    savey+=owl_message_get_numlines(owl_view_get_element(v, i));
877  }
878
879  /* If we're off the bottom of the screen, set the topmsg to curmsg
880   * and scroll upwards */
881  if (savey > recwinlines) {
882    topmsg=curmsg;
883    savey=owl_message_get_numlines(owl_view_get_element(v, i));
884    direction=OWL_DIRECTION_UPWARDS;
885  }
886 
887  /* If our bottom line is less than 1/4 down the screen then scroll up */
888  if (direction == OWL_DIRECTION_UPWARDS || direction == OWL_DIRECTION_NONE) {
889    if (savey < (recwinlines / 4)) {
890      y=0;
891      for (j=curmsg; j>=0; j--) {
892        foo=owl_message_get_numlines(owl_view_get_element(v, j));
893        /* will we run the curmsg off the screen? */
894        if ((foo+y) >= recwinlines) {
895          j++;
896          if (j>curmsg) j=curmsg;
897          break;
898        }
899        /* have saved 1/2 the screen space? */
900        y+=foo;
901        if (y > (recwinlines / 2)) break;
902      }
903      if (j<0) j=0;
904      return(j);
905    }
906  }
907
908  if (direction == OWL_DIRECTION_DOWNWARDS || direction == OWL_DIRECTION_NONE) {
909    /* If curmsg bottom line is more than 3/4 down the screen then scroll down */
910    if (savey > ((recwinlines * 3)/4)) {
911      y=0;
912      /* count lines from the top until we can save 1/2 the screen size */
913      for (j=topmsg; j<curmsg; j++) {
914        y+=owl_message_get_numlines(owl_view_get_element(v, j));
915        if (y > (recwinlines / 2)) break;
916      }
917      if (j==curmsg) {
918        j--;
919      }
920      return(j+1);
921    }
922  }
923
924  return(topmsg);
925}
926
927
928void owl_function_resize() {
929  owl_global_set_resize_pending(&g);
930}
931
932
933void owl_function_run_buffercommand() {
934  char *buff;
935
936  buff=owl_global_get_buffercommand(&g);
937  if (!strncmp(buff, "zwrite ", 7)) {
938
939    owl_function_zwrite(buff);
940  }
941}
942
943void owl_function_debugmsg(char *fmt, ...) {
944  FILE *file;
945  time_t now;
946  char buff1[LINE], buff2[LINE];
947  va_list ap;
948  va_start(ap, fmt);
949
950  if (!owl_global_is_debug_fast(&g)) return;
951
952  file=fopen(owl_global_get_debug_file(&g), "a");
953  if (!file) return;
954
955  now=time(NULL);
956  strcpy(buff1, ctime(&now));
957  buff1[strlen(buff1)-1]='\0';
958
959  owl_global_get_runtime_string(&g, buff2);
960 
961  fprintf(file, "[%i -  %s - %s]: ", (int) getpid(), buff1, buff2);
962  vfprintf(file, fmt, ap);
963  fprintf(file, "\n");
964  fclose(file);
965
966  va_end(ap);
967}
968
969
970void owl_function_refresh() {
971  owl_function_resize();
972}
973
974void owl_function_beep() {
975  if (owl_global_is_bell(&g)) {
976    beep();
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(2048);
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    if (owl_message_is_direction_out(m)) {
1564      owl_function_zwrite_setup(owl_message_get_zwriteline(m));
1565      owl_global_set_buffercommand(&g, owl_message_get_zwriteline(m));
1566    } else if (owl_message_is_type_admin(m)) {
1567      owl_function_makemsg("You cannot reply to an admin message");
1568    } else {
1569      if (owl_message_is_login(m)) {
1570        class="MESSAGE";
1571        inst="PERSONAL";
1572        to=owl_message_get_sender(m);
1573      } else if (type==1) {
1574        class="MESSAGE";
1575        inst="PERSONAL";
1576        to=owl_message_get_sender(m);
1577      } else {
1578        class=owl_message_get_class(m);
1579        inst=owl_message_get_instance(m);
1580        to=owl_message_get_recipient(m);
1581        cc=owl_message_get_cc(m);
1582        if (!strcmp(to, "") || !strcmp(to, "*")) {
1583          to="";
1584        } else if (to[0]=='@') {
1585          /* leave it, to get the realm */
1586        } else {
1587          to=owl_message_get_sender(m);
1588        }
1589      }
1590     
1591      /* create the command line */
1592      buff = owl_strdup("zwrite");
1593      if (strcasecmp(class, "message")) {
1594        buff = owl_sprintf("%s -c %s%s%s", oldbuff=buff, owl_getquoting(class), class, owl_getquoting(class));
1595        owl_free(oldbuff);
1596      }
1597      if (strcasecmp(inst, "personal")) {
1598        buff = owl_sprintf("%s -i %s%s%s", oldbuff=buff, owl_getquoting(inst), inst, owl_getquoting(inst));
1599        owl_free(oldbuff);
1600      }
1601      if (*to != '\0') {
1602        char *tmp, *oldtmp, *tmp2;
1603        tmp=short_zuser(to);
1604        if (cc) {
1605          tmp = owl_util_uniq(oldtmp=tmp, cc, "-");
1606          owl_free(oldtmp);
1607          buff = owl_sprintf("%s -C %s", oldbuff=buff, tmp);
1608          owl_free(oldbuff);
1609        } else {
1610          if (owl_global_is_smartstrip(&g)) {
1611            tmp2=tmp;
1612            tmp=smartstripped_user(tmp2);
1613            owl_free(tmp2);
1614          }
1615          buff = owl_sprintf("%s %s", oldbuff=buff, tmp);
1616          owl_free(oldbuff);
1617        }
1618        owl_free(tmp);
1619      }
1620      if (cc) owl_free(cc);
1621
1622      if (enter) {
1623        owl_history *hist = owl_global_get_cmd_history(&g);
1624        owl_history_store(hist, buff);
1625        owl_history_reset(hist);
1626        owl_function_command_norv(buff);
1627      } else {
1628        owl_function_start_command(buff);
1629      }
1630      owl_free(buff);
1631    }
1632  }
1633}
1634
1635void owl_function_zlocate(char *user, int auth) {
1636  char buff[LINE], myuser[LINE];
1637  char *ptr;
1638
1639  strcpy(myuser, user);
1640  ptr=strchr(myuser, '@');
1641  if (!ptr) {
1642    strcat(myuser, "@");
1643    strcat(myuser, ZGetRealm());
1644  }
1645
1646  owl_zephyr_zlocate(myuser, buff, auth);
1647  owl_function_popless_text(buff);
1648}
1649
1650void owl_function_start_command(char *line) {
1651  int i, j;
1652  owl_editwin *tw;
1653
1654  tw=owl_global_get_typwin(&g);
1655  owl_global_set_typwin_active(&g);
1656  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, 
1657                        owl_global_get_cmd_history(&g));
1658
1659  owl_editwin_set_locktext(tw, "command: ");
1660  owl_global_set_needrefresh(&g);
1661
1662  j=strlen(line);
1663  for (i=0; i<j; i++) {
1664    owl_editwin_process_char(tw, line[i]);
1665  }
1666  owl_editwin_redisplay(tw, 0);
1667}
1668
1669char *owl_function_exec(int argc, char **argv, char *buff, int type) {
1670  /* if type == 1 display in a popup
1671   * if type == 2 display an admin messages
1672   * if type == 0 return output
1673   * else display in a popup
1674   */
1675  char *newbuff, *redirect = " 2>&1 < /dev/null";
1676  char *out, buff2[1024];
1677  int size;
1678  FILE *p;
1679
1680  if (argc<2) {
1681    owl_function_makemsg("Wrong number of arguments to the exec command");
1682    return NULL;
1683  }
1684
1685  buff = skiptokens(buff, 1);
1686  newbuff = owl_malloc(strlen(buff)+strlen(redirect)+1);
1687  strcpy(newbuff, buff);
1688  strcat(newbuff, redirect);
1689
1690  p=popen(newbuff, "r");
1691  out=owl_malloc(1024);
1692  size=1024;
1693  strcpy(out, "");
1694  while (fgets(buff2, 1024, p)!=NULL) {
1695    size+=1024;
1696    out=owl_realloc(out, size);
1697    strcat(out, buff2);
1698  }
1699  pclose(p);
1700
1701  if (type==1) {
1702    owl_function_popless_text(out);
1703  } else if (type==0) {
1704    return out;
1705  } else if (type==2) {
1706    owl_function_adminmsg(buff, out);
1707  } else {
1708    owl_function_popless_text(out);
1709  }
1710  owl_free(out);
1711  return NULL;
1712}
1713
1714
1715char *owl_function_perl(int argc, char **argv, char *buff, int type) {
1716  /* if type == 1 display in a popup
1717   * if type == 2 display an admin messages
1718   * if type == 0 return output
1719   * else display in a popup
1720   */
1721  char *perlout;
1722
1723  if (argc<2) {
1724    owl_function_makemsg("Wrong number of arguments to perl command");
1725    return NULL;
1726  }
1727
1728  /* consume first token (argv[0]) */
1729  buff = skiptokens(buff, 1);
1730
1731  perlout = owl_config_execute(buff);
1732  if (perlout) { 
1733    if (type==1) {
1734      owl_function_popless_text(perlout);
1735    } else if (type==2) {
1736      owl_function_adminmsg(buff, perlout);
1737    } else if (type==0) {
1738      return perlout;
1739    } else {
1740      owl_function_popless_text(perlout);
1741    }
1742    owl_free(perlout);
1743  }
1744  return NULL;
1745}
1746
1747
1748void owl_function_change_view(char *filtname) {
1749  owl_view *v;
1750  owl_filter *f;
1751  int curid=-1, newpos, curmsg;
1752  owl_message *curm=NULL;
1753
1754  v=owl_global_get_current_view(&g);
1755  curmsg=owl_global_get_curmsg(&g);
1756  if (curmsg==-1) {
1757    owl_function_debugmsg("Hit the curmsg==-1 case in change_view");
1758  } else {
1759    curm=owl_view_get_element(v, curmsg);
1760    if (curm) {
1761      curid=owl_message_get_id(curm);
1762      owl_view_save_curmsgid(v, curid);
1763    }
1764  }
1765
1766  /* grab the filter */;
1767  f=owl_global_get_filter(&g, filtname);
1768  if (!f) {
1769    owl_function_makemsg("Unknown filter");
1770    return;
1771  }
1772
1773  /* free the existing view and create a new one based on the filter */
1774  owl_view_free(v);
1775  owl_view_create(v, f);
1776
1777  /* Figure out what to set the current message to.
1778   * - If the view we're leaving has messages in it, go to the closest message
1779   *   to the last message pointed to in that view.
1780   * - If the view we're leaving is empty, try to restore the position
1781   *   from the last time we were in the new view.  */
1782  if (curm) {
1783    newpos = owl_view_get_nearest_to_msgid(v, curid);
1784  } else {
1785    newpos = owl_view_get_nearest_to_saved(v);
1786  }
1787
1788  owl_global_set_curmsg(&g, newpos);
1789
1790  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
1791  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1792  owl_global_set_direction_downwards(&g);
1793}
1794
1795void owl_function_create_filter(int argc, char **argv) {
1796  owl_filter *f;
1797  owl_view *v;
1798  int ret, inuse=0;
1799
1800  if (argc < 2) {
1801    owl_function_makemsg("Wrong number of arguments to filter command");
1802    return;
1803  }
1804
1805  v=owl_global_get_current_view(&g);
1806
1807  /* don't touch the all filter */
1808  if (!strcmp(argv[1], "all")) {
1809    owl_function_makemsg("You may not change the 'all' filter.");
1810    return;
1811  }
1812
1813  /* deal with the case of trying change the filter color */
1814  if (argc==4 && !strcmp(argv[2], "-c")) {
1815    f=owl_global_get_filter(&g, argv[1]);
1816    if (!f) {
1817      owl_function_makemsg("The filter '%s' does not exist.", argv[1]);
1818      return;
1819    }
1820    owl_filter_set_color(f, owl_util_string_to_color(argv[3]));
1821    owl_global_set_needrefresh(&g);
1822    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1823    return;
1824  }
1825
1826  /* create the filter and check for errors */
1827  f=owl_malloc(sizeof(owl_filter));
1828  ret=owl_filter_init(f, argv[1], argc-2, argv+2);
1829  if (ret==-1) {
1830    owl_free(f);
1831    owl_function_makemsg("Invalid filter syntax");
1832    return;
1833  }
1834
1835  /* if the named filter is in use by the current view, remember it */
1836  if (!strcmp(owl_view_get_filtname(v), argv[1])) {
1837    inuse=1;
1838  }
1839
1840  /* if the named filter already exists, nuke it */
1841  if (owl_global_get_filter(&g, argv[1])) {
1842    owl_global_remove_filter(&g, argv[1]);
1843  }
1844
1845  /* add the filter */
1846  owl_global_add_filter(&g, f);
1847
1848  /* if it was in use by the current view then update */
1849  if (inuse) {
1850    owl_function_change_view(argv[1]);
1851  }
1852  owl_global_set_needrefresh(&g);
1853  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1854}
1855
1856void owl_function_show_filters() {
1857  owl_list *l;
1858  owl_filter *f;
1859  int i, j;
1860  owl_fmtext fm;
1861
1862  owl_fmtext_init_null(&fm);
1863
1864  l=owl_global_get_filterlist(&g);
1865  j=owl_list_get_size(l);
1866
1867  owl_fmtext_append_bold(&fm, "Filters:\n");
1868
1869  for (i=0; i<j; i++) {
1870    f=owl_list_get_element(l, i);
1871    owl_fmtext_append_normal(&fm, "   ");
1872    if (owl_global_get_hascolors(&g)) {
1873      owl_fmtext_append_normal_color(&fm, owl_filter_get_name(f), owl_filter_get_color(f));
1874    } else {
1875      owl_fmtext_append_normal(&fm, owl_filter_get_name(f));
1876    }
1877    owl_fmtext_append_normal(&fm, "\n");
1878  }
1879  owl_function_popless_fmtext(&fm);
1880  owl_fmtext_free(&fm);
1881}
1882
1883void owl_function_show_filter(char *name) {
1884  owl_filter *f;
1885  char buff[5000];
1886
1887  f=owl_global_get_filter(&g, name);
1888  if (!f) {
1889    owl_function_makemsg("There is no filter with that name");
1890    return;
1891  }
1892  owl_filter_print(f, buff);
1893  owl_function_popless_text(buff);
1894}
1895
1896void owl_function_show_zpunts() {
1897  owl_filter *f;
1898  owl_list *fl;
1899  char buff[5000];
1900  owl_fmtext fm;
1901  int i, j;
1902
1903  owl_fmtext_init_null(&fm);
1904
1905  fl=owl_global_get_puntlist(&g);
1906  j=owl_list_get_size(fl);
1907  owl_fmtext_append_bold(&fm, "Active zpunt filters:\n");
1908
1909  for (i=0; i<j; i++) {
1910    f=owl_list_get_element(fl, i);
1911    owl_filter_print(f, buff);
1912    owl_fmtext_append_normal(&fm, buff);
1913  }
1914  owl_function_popless_fmtext(&fm);
1915  owl_fmtext_free(&fm);
1916}
1917
1918char *owl_function_fastclassinstfilt(char *class, char *instance) {
1919  /* creates a filter for a class, instance if one doesn't exist.
1920   * If instance is null then apply for all messgaes in the class.
1921   * returns the name of the filter, which the caller must free.*/
1922  owl_list *fl;
1923  owl_filter *f;
1924  char *argbuff, *filtname;
1925  int len;
1926
1927  fl=owl_global_get_filterlist(&g);
1928
1929  /* name for the filter */
1930  len=strlen(class)+30;
1931  if (instance) len+=strlen(instance);
1932  filtname=owl_malloc(len);
1933  if (!instance) {
1934    sprintf(filtname, "class-%s", class);
1935  } else {
1936    sprintf(filtname, "class-%s-instance-%s", class, instance);
1937  }
1938  downstr(filtname);
1939
1940  /* if it already exists then go with it.  This lets users override */
1941  if (owl_global_get_filter(&g, filtname)) {
1942    return filtname;
1943  }
1944
1945  /* create the new filter */
1946  argbuff=owl_malloc(len+20);
1947  sprintf(argbuff, "( class ^%s$ )", class);
1948  if (instance) {
1949    sprintf(argbuff, "%s and ( instance ^%s$ )", argbuff, instance);
1950  }
1951
1952  f=owl_malloc(sizeof(owl_filter));
1953  owl_filter_init_fromstring(f, filtname, argbuff);
1954
1955  /* add it to the global list */
1956  owl_global_add_filter(&g, f);
1957
1958  owl_free(argbuff);
1959  return filtname;
1960}
1961
1962char *owl_function_fastuserfilt(char *user) {
1963  owl_filter *f;
1964  char *argbuff, *longuser, *shortuser, *filtname;
1965
1966  /* stick the local realm on if it's not there */
1967  longuser=long_zuser(user);
1968  shortuser=short_zuser(user);
1969
1970  /* name for the filter */
1971  filtname=owl_malloc(strlen(shortuser)+20);
1972  sprintf(filtname, "user-%s", shortuser);
1973
1974  /* if it already exists then go with it.  This lets users override */
1975  if (owl_global_get_filter(&g, filtname)) {
1976    return filtname;
1977  }
1978
1979  /* create the new-internal filter */
1980  f=owl_malloc(sizeof(owl_filter));
1981
1982  argbuff=owl_malloc(strlen(longuser)+1000);
1983  sprintf(argbuff, "( type ^zephyr$ and ( class ^message$ and instance ^personal$ and ");
1984  sprintf(argbuff, "%s ( ( direction ^in$ and sender ^%s$ ) or ( direction ^out$ and recipient ^%s$ ) ) )", argbuff, longuser, longuser);
1985  sprintf(argbuff, "%s or ( ( class ^login$ ) and ( sender ^%s$ ) ) )", argbuff, longuser);
1986
1987  owl_filter_init_fromstring(f, filtname, argbuff);
1988
1989  /* add it to the global list */
1990  owl_global_add_filter(&g, f);
1991
1992  /* free stuff */
1993  owl_free(argbuff);
1994  owl_free(longuser);
1995  owl_free(shortuser);
1996
1997  return filtname;
1998}
1999
2000char *owl_function_fasttypefilt(char *type) {
2001  owl_filter *f;
2002  char *argbuff, *filtname;
2003
2004  /* name for the filter */
2005  filtname=owl_sprintf("type-%s", type);
2006
2007  /* if it already exists then go with it.  This lets users override */
2008  if (owl_global_get_filter(&g, filtname)) {
2009    return filtname;
2010  }
2011
2012  /* create the new-internal filter */
2013  f=owl_malloc(sizeof(owl_filter));
2014
2015  argbuff = owl_sprintf("type ^%s$", type);
2016
2017  owl_filter_init_fromstring(f, filtname, argbuff);
2018
2019  /* add it to the global list */
2020  owl_global_add_filter(&g, f);
2021
2022  /* free stuff */
2023  owl_free(argbuff);
2024
2025  return filtname;
2026}
2027
2028/* If flag is 1, marks for deletion.  If flag is 0,
2029 * unmarks for deletion. */
2030void owl_function_delete_curview_msgs(int flag) {
2031  owl_view *v;
2032  int i, j;
2033
2034  v=owl_global_get_current_view(&g);
2035  j=owl_view_get_size(v);
2036  for (i=0; i<j; i++) {
2037    if (flag == 1) {
2038      owl_message_mark_delete(owl_view_get_element(v, i));
2039    } else if (flag == 0) {
2040      owl_message_unmark_delete(owl_view_get_element(v, i));
2041    }
2042  }
2043
2044  owl_function_makemsg("%i messages marked for %sdeletion", j, flag?"":"un");
2045
2046  owl_mainwin_redisplay(owl_global_get_mainwin(&g)); 
2047}
2048
2049char *owl_function_smartfilter(int type) {
2050  /* Returns the name of a filter, or null.  The caller
2051   * must free this name.  */
2052  /* if the curmsg is a personal message return a filter name
2053   *    to the converstaion with that user.
2054   * If the curmsg is a class message, instance foo, recip *
2055   *    message, return a filter name to the class, inst.
2056   * If the curmsg is a class message and type==0 then
2057   *    return a filter name for just the class.
2058   * If the curmsg is a class message and type==1 then
2059   *    return a filter name for the class and instance.
2060   */
2061  owl_view *v;
2062  owl_message *m;
2063  char *zperson, *filtname=NULL;
2064 
2065  v=owl_global_get_current_view(&g);
2066  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2067
2068  if (!m || owl_view_get_size(v)==0) {
2069    owl_function_makemsg("No message selected\n");
2070    return(NULL);
2071  }
2072
2073  /* very simple handling of admin messages for now */
2074  if (owl_message_is_type_admin(m)) {
2075    return(owl_function_fasttypefilt("admin"));
2076  }
2077
2078  /* narrow personal and login messages to the sender or recip as appropriate */
2079  if (owl_message_is_personal(m) || owl_message_is_login(m)) {
2080    if (owl_message_is_type_zephyr(m)) {
2081      if (owl_message_is_direction_in(m)) {
2082        zperson=short_zuser(owl_message_get_sender(m));
2083      } else {
2084        zperson=short_zuser(owl_message_get_recipient(m));
2085      }
2086      filtname=owl_function_fastuserfilt(zperson);
2087      owl_free(zperson);
2088      return(filtname);
2089    }
2090    return(NULL);
2091  }
2092
2093  /* narrow class MESSAGE, instance foo, recip * messages to class, inst */
2094  if (!strcasecmp(owl_message_get_class(m), "message") &&
2095      !owl_message_is_personal(m)) {
2096    filtname=owl_function_fastclassinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2097    return(filtname);
2098  }
2099
2100  /* otherwise narrow to the class */
2101  if (type==0) {
2102    filtname=owl_function_fastclassinstfilt(owl_message_get_class(m), NULL);
2103  } else if (type==1) {
2104    filtname=owl_function_fastclassinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2105  }
2106  return(filtname);
2107}
2108
2109void owl_function_smartzpunt(int type) {
2110  /* Starts a zpunt command based on the current class,instance pair.
2111   * If type=0, uses just class.  If type=1, uses instance as well. */
2112  owl_view *v;
2113  owl_message *m;
2114  char *cmd, *cmdprefix, *mclass, *minst;
2115 
2116  v=owl_global_get_current_view(&g);
2117  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2118
2119  if (!m || owl_view_get_size(v)==0) {
2120    owl_function_makemsg("No message selected\n");
2121    return;
2122  }
2123
2124  /* for now we skip admin messages. */
2125  if (owl_message_is_type_admin(m)
2126      || owl_message_is_login(m)
2127      || !owl_message_is_type_zephyr(m)) {
2128    owl_function_makemsg("smartzpunt doesn't support this message type.");
2129    return;
2130  }
2131
2132  mclass = owl_message_get_class(m);
2133  minst = owl_message_get_instance(m);
2134  if (!mclass || !*mclass || *mclass==' '
2135      || (!strcasecmp(mclass, "message") && !strcasecmp(minst, "personal"))
2136      || (type && (!minst || !*minst|| *minst==' '))) {
2137    owl_function_makemsg("smartzpunt can't safely do this for <%s,%s>",
2138                         mclass, minst);
2139  } else {
2140    cmdprefix = "start-command zpunt ";
2141    cmd = owl_malloc(strlen(cmdprefix)+strlen(mclass)+strlen(minst)+3);
2142    strcpy(cmd, cmdprefix);
2143    strcat(cmd, mclass);
2144    if (type) {
2145      strcat(cmd, " ");
2146      strcat(cmd, minst);
2147    } else {
2148      strcat(cmd, " *");
2149    }
2150    owl_function_command(cmd);
2151    owl_free(cmd);
2152  }
2153}
2154
2155
2156
2157void owl_function_color_current_filter(char *color) {
2158  owl_filter *f;
2159  char *name;
2160
2161  name=owl_view_get_filtname(owl_global_get_current_view(&g));
2162  f=owl_global_get_filter(&g, name);
2163  if (!f) {
2164    owl_function_makemsg("Unknown filter");
2165    return;
2166  }
2167
2168  /* don't touch the all filter */
2169  if (!strcmp(name, "all")) {
2170    owl_function_makemsg("You may not change the 'all' filter.");
2171    return;
2172  }
2173
2174  /* deal with the case of trying change the filter color */
2175  owl_filter_set_color(f, owl_util_string_to_color(color));
2176  owl_global_set_needrefresh(&g);
2177  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2178}
2179
2180void owl_function_show_colors() {
2181  owl_fmtext fm;
2182
2183  owl_fmtext_init_null(&fm);
2184  owl_fmtext_append_normal_color(&fm, "default\n", OWL_COLOR_DEFAULT);
2185  owl_fmtext_append_normal_color(&fm, "red\n", OWL_COLOR_RED);
2186  owl_fmtext_append_normal_color(&fm, "green\n", OWL_COLOR_GREEN);
2187  owl_fmtext_append_normal_color(&fm, "yellow\n", OWL_COLOR_YELLOW);
2188  owl_fmtext_append_normal_color(&fm, "blue\n", OWL_COLOR_BLUE);
2189  owl_fmtext_append_normal_color(&fm, "magenta\n", OWL_COLOR_MAGENTA);
2190  owl_fmtext_append_normal_color(&fm, "cyan\n", OWL_COLOR_CYAN);
2191  owl_fmtext_append_normal_color(&fm, "white\n", OWL_COLOR_WHITE);
2192
2193  owl_function_popless_fmtext(&fm);
2194  owl_fmtext_free(&fm);
2195}
2196
2197void owl_function_zpunt(char *class, char *inst, char *recip, int direction) {
2198  /* add the given class, inst, recip to the punt list for filtering.
2199   *   if direction==0 then punt
2200   *   if direction==1 then unpunt */
2201  owl_filter *f;
2202  owl_list *fl;
2203  char *buff;
2204  int ret, i, j;
2205
2206  fl=owl_global_get_puntlist(&g);
2207
2208  /* first, create the filter */
2209  f=malloc(sizeof(owl_filter));
2210  buff=malloc(strlen(class)+strlen(inst)+strlen(recip)+100);
2211  if (!strcmp(recip, "*")) {
2212    sprintf(buff, "class ^%s$ and instance ^%s$", class, inst);
2213  } else {
2214    sprintf(buff, "class ^%s$ and instance ^%s$ and recipient %s", class, inst, recip);
2215  }
2216  owl_function_debugmsg("About to filter %s", buff);
2217  ret=owl_filter_init_fromstring(f, "punt-filter", buff);
2218  owl_free(buff);
2219  if (ret) {
2220    owl_function_makemsg("Error creating filter for zpunt");
2221    owl_filter_free(f);
2222    return;
2223  }
2224
2225  /* Check for an identical filter */
2226  j=owl_list_get_size(fl);
2227  for (i=0; i<j; i++) {
2228    if (owl_filter_equiv(f, owl_list_get_element(fl, i))) {
2229      /* if we're punting, then just silently bow out on this duplicate */
2230      if (direction==0) {
2231        owl_filter_free(f);
2232        return;
2233      }
2234
2235      /* if we're unpunting, then remove this filter from the puntlist */
2236      if (direction==1) {
2237        owl_filter_free(owl_list_get_element(fl, i));
2238        owl_list_remove_element(fl, i);
2239        return;
2240      }
2241    }
2242  }
2243
2244  /* If we're punting, add the filter to the global punt list */
2245  if (direction==0) {
2246    owl_list_append_element(fl, f);
2247  }
2248}
2249
2250void owl_function_activate_keymap(char *keymap) {
2251  if (!owl_keyhandler_activate(owl_global_get_keyhandler(&g), keymap)) {
2252    owl_function_makemsg("Unable to activate keymap '%s'", keymap);
2253  }
2254}
2255
2256
2257void owl_function_show_keymaps() {
2258  owl_list l;
2259  owl_fmtext fm;
2260  owl_keymap *km;
2261  owl_keyhandler *kh;
2262  int i, numkm;
2263  char *kmname;
2264
2265  kh = owl_global_get_keyhandler(&g);
2266  owl_fmtext_init_null(&fm);
2267  owl_fmtext_append_bold(&fm, "Keymaps:   ");
2268  owl_fmtext_append_normal(&fm, "(use 'show keymap <name>' for details)\n");
2269  owl_keyhandler_get_keymap_names(kh, &l);
2270  owl_fmtext_append_list(&fm, &l, "\n", owl_function_keymap_summary);
2271  owl_fmtext_append_normal(&fm, "\n");
2272
2273  numkm = owl_list_get_size(&l);
2274  for (i=0; i<numkm; i++) {
2275    kmname = owl_list_get_element(&l, i);
2276    km = owl_keyhandler_get_keymap(kh, kmname);
2277    owl_fmtext_append_bold(&fm, "\n\n----------------------------------------------------------------------------------------------------\n\n");
2278    owl_keymap_get_details(km, &fm);   
2279  }
2280  owl_fmtext_append_normal(&fm, "\n");
2281 
2282  owl_function_popless_fmtext(&fm);
2283  owl_keyhandler_keymap_namelist_free(&l);
2284  owl_fmtext_free(&fm);
2285}
2286
2287char *owl_function_keymap_summary(void *name) {
2288  owl_keymap *km
2289    = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
2290  if (km) return owl_keymap_summary(km);
2291  else return(NULL);
2292}
2293
2294/* TODO: implement for real */
2295void owl_function_show_keymap(char *name) {
2296  owl_fmtext fm;
2297  owl_keymap *km;
2298
2299  owl_fmtext_init_null(&fm);
2300  km = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
2301  if (km) {
2302    owl_keymap_get_details(km, &fm);
2303  } else {
2304    owl_fmtext_append_normal(&fm, "No such keymap...\n");
2305  } 
2306  owl_function_popless_fmtext(&fm);
2307  owl_fmtext_free(&fm);
2308}
2309
2310void owl_function_help_for_command(char *cmdname) {
2311  owl_fmtext fm;
2312
2313  owl_fmtext_init_null(&fm);
2314  owl_cmd_get_help(owl_global_get_cmddict(&g), cmdname, &fm);
2315  owl_function_popless_fmtext(&fm); 
2316  owl_fmtext_free(&fm);
2317}
2318
2319void owl_function_search_start(char *string, int direction) {
2320  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
2321  owl_global_set_search_active(&g, string);
2322  owl_function_search_helper(0, direction);
2323}
2324
2325void owl_function_search_continue(int direction) {
2326  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
2327  owl_function_search_helper(1, direction);
2328}
2329
2330void owl_function_search_helper(int mode, int direction) {
2331  /* move to a message that contains the string.  If direction is
2332   * OWL_DIRECTION_DOWNWARDS then search fowards, if direction is
2333   * OWL_DIRECTION_UPWARDS then search backwards.
2334   *
2335   * If mode==0 then it will stay on the current message if it
2336   * contains the string.
2337   */
2338
2339  owl_view *v;
2340  int viewsize, i, curmsg, start;
2341  owl_message *m;
2342
2343  v=owl_global_get_current_view(&g);
2344  viewsize=owl_view_get_size(v);
2345  curmsg=owl_global_get_curmsg(&g);
2346 
2347  if (viewsize==0) {
2348    owl_function_makemsg("No messages present");
2349    return;
2350  }
2351
2352  if (mode==0) {
2353    start=curmsg;
2354  } else if (direction==OWL_DIRECTION_DOWNWARDS) {
2355    start=curmsg+1;
2356  } else {
2357    start=curmsg-1;
2358  }
2359
2360  /* bounds check */
2361  if (start>=viewsize || start<0) {
2362    owl_function_makemsg("No further matches found");
2363    return;
2364  }
2365
2366  for (i=start; i<viewsize && i>=0;) {
2367    m=owl_view_get_element(v, i);
2368    if (owl_message_search(m, owl_global_get_search_string(&g))) {
2369      owl_global_set_curmsg(&g, i);
2370      owl_function_calculate_topmsg(direction);
2371      owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2372      if (direction==OWL_DIRECTION_DOWNWARDS) {
2373        owl_global_set_direction_downwards(&g);
2374      } else {
2375        owl_global_set_direction_upwards(&g);
2376      }
2377      return;
2378    }
2379    if (direction==OWL_DIRECTION_DOWNWARDS) {
2380      i++;
2381    } else {
2382      i--;
2383    }
2384  }
2385  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2386  owl_function_makemsg("No matches found");
2387}
2388
2389
2390/* strips formatting from ztext and returns the unformatted text.
2391 * caller is responsible for freeing. */
2392char *owl_function_ztext_stylestrip(char *zt) {
2393  owl_fmtext fm;
2394  char *plaintext;
2395
2396  owl_fmtext_init_null(&fm);
2397  owl_fmtext_append_ztext(&fm, zt);
2398  plaintext = owl_fmtext_print_plain(&fm);
2399  owl_fmtext_free(&fm);
2400  return(plaintext);
2401}
2402
2403/* popup a znol listing.  If file is NULL use the default .anyone */
2404/* this doesn't obey 'elapsed' or 'timesort' yet */
2405void owl_function_zlist(char *file, int elapsed, int timesort) {
2406  char *ourfile, *tmp, buff[LINE], *line;
2407  FILE *f;
2408  int numlocs, ret, i;
2409  ZLocations_t location[200];
2410  owl_fmtext fm;
2411
2412  if (file==NULL) {
2413    tmp=owl_global_get_homedir(&g);
2414    if (!tmp) {
2415      owl_function_makemsg("Could not determine home directory");
2416      return;
2417    }
2418    ourfile=owl_malloc(strlen(tmp)+50);
2419    sprintf(ourfile, "%s/.anyone", owl_global_get_homedir(&g));
2420  } else {
2421    ourfile=owl_strdup(file);
2422  }
2423
2424  f=fopen(ourfile, "r");
2425  if (!f) {
2426    owl_function_makemsg("Error opening file %s", ourfile);
2427    return;
2428  }
2429
2430  owl_fmtext_init_null(&fm);
2431   
2432  while (fgets(buff, LINE, f)!=NULL) {
2433    /* ignore comments, blank lines etc. */
2434    if (buff[0]=='#') continue;
2435    if (buff[0]=='\n') continue;
2436    if (buff[0]=='\0') continue;
2437
2438    /* strip the \n */
2439    buff[strlen(buff)-1]='\0';
2440
2441    /* ingore from # on */
2442    tmp=strchr(buff, '#');
2443    if (tmp) tmp[0]='\0';
2444
2445    /* ingore from SPC */
2446    tmp=strchr(buff, ' ');
2447    if (tmp) tmp[0]='\0';
2448
2449    /* stick on the local realm. */
2450    if (!strchr(buff, '@')) {
2451      strcat(buff, "@");
2452      strcat(buff, ZGetRealm());
2453    }
2454
2455    ret=ZLocateUser(buff, &numlocs, ZAUTH);
2456    if (ret!=ZERR_NONE) {
2457      owl_function_makemsg("Error getting location for %s", buff);
2458      continue;
2459    }
2460
2461    numlocs=200;
2462    ret=ZGetLocations(location, &numlocs);
2463    if (ret==0) {
2464      for (i=0; i<numlocs; i++) {
2465        line=malloc(strlen(location[i].host)+strlen(location[i].time)+strlen(location[i].tty)+100);
2466        tmp=short_zuser(buff);
2467        sprintf(line, "%-10.10s %-24.24s %-12.12s  %20.20s\n",
2468                tmp,
2469                location[i].host,
2470                location[i].tty,
2471                location[i].time);
2472        owl_fmtext_append_normal(&fm, line);
2473        owl_free(tmp);
2474      }
2475      if (numlocs>=200) {
2476        owl_fmtext_append_normal(&fm, "Too many locations found for this user, truncating.\n");
2477      }
2478    }
2479  }
2480  fclose(f);
2481
2482  owl_function_popless_fmtext(&fm);
2483  owl_fmtext_free(&fm);
2484
2485  owl_free(ourfile);
2486}
Note: See TracBrowser for help on using the repository browser.