source: functions.c @ 4b464a4

barnowl_perlaimdebianowlrelease-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 4b464a4 was 4b464a4, checked in by James M. Kretchmar <kretch@mit.edu>, 18 years ago
Messages now have a direciton (in, out or none). Filters can this direction Outbound messages are no longer type 'admin' but are of the appropriate message type (i.e. 'zephyr') and are direction 'out'. Smartnarrow now works on outgoing messages 'info' updated to show more information for admin and outgoing messages Renamed pretty_sender to short_zuser and renamed long_sender to long_zuser
  • Property mode set to 100644
File size: 63.7 KB
Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <signal.h>
5#include <string.h>
6#include <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) {
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", owl_zwrite_get_recip_n(&z, 0));
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}
132
133void owl_function_zwrite_setup(char *line) {
134  owl_editwin *e;
135  char buff[1024];
136  owl_zwrite z;
137  int ret;
138
139  /* check the arguments */
140  ret=owl_zwrite_create_from_line(&z, line);
141  if (ret) {
142    owl_function_makemsg("Error in zwrite arugments");
143    owl_zwrite_free(&z);
144    return;
145  }
146
147  /* send a ping if necessary */
148  if (owl_global_is_txping(&g)) {
149    owl_zwrite_send_ping(&z);
150  }
151  owl_zwrite_free(&z);
152
153  /* create and setup the editwin */
154  e=owl_global_get_typwin(&g);
155  owl_editwin_new_style(e, OWL_EDITWIN_STYLE_MULTILINE,
156                        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 admin 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);
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; 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    if (owl_message_is_delete(owl_view_get_element(v, curmsg))) {
423      for (i=curmsg; i>0; i--) {
424        if (!owl_message_is_delete(owl_view_get_element(v, i))) {
425          owl_global_set_curmsg(&g, i);
426          break;
427        }
428      }
429    }
430  }
431
432  /* expunge the message list */
433  owl_messagelist_expunge(ml);
434
435  /* update all views (we only have one right now) */
436  owl_view_recalculate(v);
437
438  if (curmsg>owl_view_get_size(v)-1) {
439    owl_global_set_curmsg(&g, owl_view_get_size(v)-1);
440    if (owl_global_get_curmsg(&g)<0) {
441      owl_global_set_curmsg(&g, 0);
442    }
443    owl_function_calculate_topmsg(OWL_DIRECTION_NONE);
444  }
445
446  /* if there are no messages set the direction to down in case we
447     delete everything upwards */
448  owl_global_set_direction_downwards(&g);
449 
450  owl_function_makemsg("Messages expunged");
451  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
452}
453
454
455void owl_function_firstmsg() {
456  owl_global_set_curmsg(&g, 0);
457  owl_global_set_topmsg(&g, 0);
458  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
459  owl_global_set_direction_downwards(&g);
460}
461
462void owl_function_lastmsg_noredisplay() {
463  int oldcurmsg, curmsg;
464  owl_view *v;
465
466  v=owl_global_get_current_view(&g);
467  oldcurmsg=owl_global_get_curmsg(&g);
468  curmsg=owl_view_get_size(v)-1; 
469  if (curmsg<0) curmsg=0;
470  owl_global_set_curmsg(&g, curmsg);
471  if (oldcurmsg < curmsg) {
472    owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
473  } else if (curmsg<owl_view_get_size(v)) {
474    /* If already at the end, blank the screen and move curmsg
475     * past the end of the messages. */
476    owl_global_set_topmsg(&g, curmsg+1);
477    owl_global_set_curmsg(&g, curmsg+1);
478  } 
479  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
480  owl_global_set_direction_downwards(&g);
481}
482
483void owl_function_lastmsg() {
484  owl_function_lastmsg_noredisplay();
485  owl_mainwin_redisplay(owl_global_get_mainwin(&g)); 
486}
487
488void owl_function_shift_right() {
489  owl_global_set_rightshift(&g, owl_global_get_rightshift(&g)+10);
490  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
491  owl_global_set_needrefresh(&g);
492}
493
494
495void owl_function_shift_left() {
496  int shift;
497
498  shift=owl_global_get_rightshift(&g);
499  if (shift>=10) {
500    owl_global_set_rightshift(&g, shift-10);
501    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
502    owl_global_set_needrefresh(&g);
503  } else {
504    owl_function_beep();
505    owl_function_makemsg("Already full left");
506  }
507}
508
509
510void owl_function_unsuball() {
511  unsuball();
512  owl_function_makemsg("Unsubscribed from all messages.");
513}
514
515void owl_function_loadsubs(char *file) {
516  int ret;
517  ret=owl_zephyr_loadsubs(file);
518  if (ret==0) {
519    owl_function_makemsg("Subscribed to messages from file.");
520  } else if (ret==-1) {
521    owl_function_makemsg("Could not open file.");
522  } else {
523    owl_function_makemsg("Error subscribing to messages from file.");
524  }
525}
526
527void owl_function_suspend() {
528  endwin();
529  printf("\n");
530  kill(getpid(), SIGSTOP);
531
532  /* resize to reinitialize all the windows when we come back */
533  owl_command_resize();
534}
535
536void owl_function_zaway_toggle() {
537  if (!owl_global_is_zaway(&g)) {
538    owl_global_set_zaway_msg(&g, owl_global_get_zaway_msg_default(&g));
539    owl_function_zaway_on();
540  } else {
541    owl_function_zaway_off();
542  }
543}
544
545void owl_function_zaway_on() {
546  owl_global_set_zaway_on(&g);
547  owl_function_makemsg("zaway set (%s)", owl_global_get_zaway_msg(&g));
548}
549
550void owl_function_zaway_off() {
551  owl_global_set_zaway_off(&g);
552  owl_function_makemsg("zaway off");
553}
554
555void owl_function_quit() {
556  char *ret;
557 
558  /* zlog out if we need to */
559  if (owl_global_is_shutdownlogout(&g)) {
560    owl_function_zlog_out();
561  }
562
563  /* execute the commands in shutdown */
564  ret = owl_config_execute("owl::shutdown();");
565  if (ret) owl_free(ret);
566
567  /* final clean up */
568  unsuball();
569  ZClosePort();
570  endwin();
571  owl_function_debugmsg("Quitting Owl");
572  exit(0);
573}
574
575
576void owl_function_zlog_in() {
577  char *exposure, *eset;
578  int ret;
579
580  eset=EXPOSE_REALMVIS;
581  exposure=ZGetVariable("exposure");
582  if (exposure==NULL) {
583    eset=EXPOSE_REALMVIS;
584  } else if (!strcasecmp(exposure,EXPOSE_NONE)) {
585    eset = EXPOSE_NONE;
586  } else if (!strcasecmp(exposure,EXPOSE_OPSTAFF)) {
587    eset = EXPOSE_OPSTAFF;
588  } else if (!strcasecmp(exposure,EXPOSE_REALMVIS)) {
589    eset = EXPOSE_REALMVIS;
590  } else if (!strcasecmp(exposure,EXPOSE_REALMANN)) {
591    eset = EXPOSE_REALMANN;
592  } else if (!strcasecmp(exposure,EXPOSE_NETVIS)) {
593    eset = EXPOSE_NETVIS;
594  } else if (!strcasecmp(exposure,EXPOSE_NETANN)) {
595    eset = EXPOSE_NETANN;
596  }
597   
598  ret=ZSetLocation(eset);
599  if (ret != ZERR_NONE) {
600    /*
601      char buff[LINE];
602      sprintf(buff, "Error setting location: %s", error_message(ret));
603      owl_function_makemsg(buff);
604    */
605  }
606}
607
608void owl_function_zlog_out() {
609  int ret;
610 
611  ret=ZUnsetLocation();
612  if (ret != ZERR_NONE) {
613    /*
614      char buff[LINE];
615      sprintf(buff, "Error unsetting location: %s", error_message(ret));
616      owl_function_makemsg(buff);
617    */
618  }
619}
620
621
622void owl_function_makemsg(char *fmt, ...) {
623  va_list ap;
624  char buff[2048];
625
626  va_start(ap, fmt);
627  werase(owl_global_get_curs_msgwin(&g));
628 
629  vsnprintf(buff, 2048, fmt, ap);
630  owl_function_debugmsg("makemsg: %s", buff);
631  waddstr(owl_global_get_curs_msgwin(&g), buff); 
632  wnoutrefresh(owl_global_get_curs_msgwin(&g));
633  owl_global_set_needrefresh(&g);
634  va_end(ap);
635}
636
637void owl_function_errormsg(char *fmt, ...) {
638  va_list ap;
639  char buff[2048];
640
641  va_start(ap, fmt);
642  werase(owl_global_get_curs_msgwin(&g));
643 
644  vsnprintf(buff, 2048, fmt, ap);
645  owl_function_debugmsg("ERROR: %s", buff);
646  waddstr(owl_global_get_curs_msgwin(&g), buff); 
647  waddstr(owl_global_get_curs_msgwin(&g), "ERROR: "); 
648  wnoutrefresh(owl_global_get_curs_msgwin(&g));
649  owl_global_set_needrefresh(&g);
650  va_end(ap);
651}
652
653
654void owl_function_openurl() {
655  /* visit the first url in the current message */
656  owl_message *m;
657  owl_view *v;
658  char *ptr1, *ptr2, *text, url[LINE], tmpbuff[LINE];
659  int webbrowser;
660
661  webbrowser = owl_global_get_webbrowser(&g);
662
663  if (webbrowser < 0 || webbrowser == OWL_WEBBROWSER_NONE) {
664    owl_function_makemsg("No browser selected");
665    return;
666  }
667
668  v=owl_global_get_current_view(&g);
669 
670  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
671
672  if (!m || owl_view_get_size(v)==0) {
673    owl_function_makemsg("No current message selected");
674    return;
675  }
676
677  text=owl_message_get_text(m);
678
679  /* First look for a good URL */ 
680  if ((ptr1=strstr(text, "http://"))!=NULL) {
681    ptr2=strpbrk(ptr1, " \n\t");
682    if (ptr2) {
683      strncpy(url, ptr1, ptr2-ptr1+1);
684      url[ptr2-ptr1+1]='\0';
685    } else {
686      strcpy(url, ptr1);
687    }
688
689    /* if we had <http strip a trailing > */
690    if (ptr1>text && ptr1[-1]=='<') {
691      if (url[strlen(url)-1]=='>') {
692        url[strlen(url)-1]='\0';
693      }
694    }
695  } else if ((ptr1=strstr(text, "https://"))!=NULL) {
696    /* Look for an https URL */ 
697    ptr2=strpbrk(ptr1, " \n\t");
698    if (ptr2) {
699      strncpy(url, ptr1, ptr2-ptr1+1);
700      url[ptr2-ptr1+1]='\0';
701    } else {
702      strcpy(url, ptr1);
703    }
704   
705    /* if we had <http strip a trailing > */
706    if (ptr1>text && ptr1[-1]=='<') {
707      if (url[strlen(url)-1]=='>') {
708        url[strlen(url)-1]='\0';
709      }
710    }
711  } else if ((ptr1=strstr(text, "www."))!=NULL) {
712    /* if we can't find a real url look for www.something */
713    ptr2=strpbrk(ptr1, " \n\t");
714    if (ptr2) {
715      strncpy(url, ptr1, ptr2-ptr1+1);
716      url[ptr2-ptr1+1]='\0';
717    } else {
718      strcpy(url, ptr1);
719    }
720  } else {
721    owl_function_beep();
722    owl_function_makemsg("Could not find URL to open.");
723    return;
724  }
725
726  /* Make sure there aren't any quotes or \'s in the url */
727  for (ptr1 = url; *ptr1; ptr1++) {
728    if (*ptr1 == '"' || *ptr1 == '\\') {
729      owl_function_beep();
730      owl_function_makemsg("URL contains invalid characters.");
731      return;
732    }
733  }
734 
735  /* NOTE: There are potentially serious security issues here... */
736
737  /* open the page */
738  owl_function_makemsg("Opening %s", url);
739  if (webbrowser == OWL_WEBBROWSER_NETSCAPE) {
740    snprintf(tmpbuff, LINE, "netscape -remote \"openURL(%s)\" > /dev/null 2> /dev/null", url);
741    system(tmpbuff); 
742  } else if (webbrowser == OWL_WEBBROWSER_GALEON) {
743    snprintf(tmpbuff, LINE, "galeon \"%s\" > /dev/null 2> /dev/null &", url);
744    system(tmpbuff); 
745  } else if (webbrowser == OWL_WEBBROWSER_OPERA) {
746    snprintf(tmpbuff, LINE, "opera \"%s\" > /dev/null 2> /dev/null &", url);
747    system(tmpbuff); 
748  }
749}
750
751void owl_function_calculate_topmsg(int direction) {
752  int recwinlines, topmsg, curmsg;
753  owl_view *v;
754
755  v=owl_global_get_current_view(&g);
756  curmsg=owl_global_get_curmsg(&g);
757  topmsg=owl_global_get_topmsg(&g);
758  recwinlines=owl_global_get_recwin_lines(&g);
759
760  if (owl_view_get_size(v) < 1) {
761    return;
762  }
763
764  switch (owl_global_get_scrollmode(&g)) {
765  case OWL_SCROLLMODE_TOP:
766    topmsg = owl_function_calculate_topmsg_top(direction, v, curmsg,
767                                               topmsg, recwinlines);
768    break;
769  case OWL_SCROLLMODE_NEARTOP:
770    topmsg = owl_function_calculate_topmsg_neartop(direction, v, curmsg, 
771                                                   topmsg, recwinlines);
772    break;
773  case OWL_SCROLLMODE_CENTER:
774    topmsg = owl_function_calculate_topmsg_center(direction, v, curmsg,
775                                                  topmsg, recwinlines);
776    break;
777  case OWL_SCROLLMODE_PAGED:
778    topmsg = owl_function_calculate_topmsg_paged(direction, v, curmsg, 
779                                                 topmsg, recwinlines, 0);
780    break;
781  case OWL_SCROLLMODE_PAGEDCENTER:
782    topmsg = owl_function_calculate_topmsg_paged(direction, v, curmsg, 
783                                                 topmsg, recwinlines, 1);
784    break;
785  case OWL_SCROLLMODE_NORMAL:
786  default:
787    topmsg = owl_function_calculate_topmsg_normal(direction, v, curmsg,
788                                                  topmsg, recwinlines);
789  }
790  owl_global_set_topmsg(&g, topmsg);
791}
792
793/* Returns what the new topmsg should be. 
794 * Passed the last direction of movement,
795 * the current view,
796 * the current message number in the view,
797 * the top message currently being displayed,
798 * and the number of lines in the recwin.
799 */
800int owl_function_calculate_topmsg_top(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines) {
801  return curmsg;
802}
803
804int owl_function_calculate_topmsg_neartop(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines) {
805  if (curmsg>0 
806      && (owl_message_get_numlines(owl_view_get_element(v, curmsg-1))
807          <  recwinlines/2)) {
808    return curmsg-1;
809  } else {
810    return curmsg;
811  }
812}
813 
814int owl_function_calculate_topmsg_center(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines) {
815  int i, last, lines;
816
817  last = curmsg;
818  lines = 0;
819  for (i=curmsg-1; i>=0; i--) {
820    lines += owl_message_get_numlines(owl_view_get_element(v, i));
821    if (lines > recwinlines/2) break;
822    last = i;
823  }
824  return last;
825}
826 
827int owl_function_calculate_topmsg_paged(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines, int center_on_page) {
828  int i, last, lines, savey;
829 
830  /* If we're off the top of the screen, scroll up such that the
831   * curmsg is near the botton of the screen. */
832  if (curmsg < topmsg) {
833    last = curmsg;
834    lines = 0;
835    for (i=curmsg; i>=0; i--) {
836      lines += owl_message_get_numlines(owl_view_get_element(v, i));
837      if (lines > recwinlines) break;
838    last = i;
839    }
840    if (center_on_page) {
841      return owl_function_calculate_topmsg_center(direction, v, curmsg, 0, recwinlines);
842    } else {
843      return last;
844    }
845  }
846
847  /* Find number of lines from top to bottom of curmsg (store in savey) */
848  savey=0;
849  for (i=topmsg; i<=curmsg; i++) {
850    savey+=owl_message_get_numlines(owl_view_get_element(v, i));
851  }
852
853  /* if we're off the bottom of the screen, scroll down */
854  if (savey > recwinlines) {
855    if (center_on_page) {
856      return owl_function_calculate_topmsg_center(direction, v, curmsg, 0, recwinlines);
857    } else {
858      return curmsg;
859    }
860  }
861
862  /* else just stay as we are... */
863  return topmsg;
864}
865
866
867int owl_function_calculate_topmsg_normal(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines) {
868  int savey, j, i, foo, y;
869 
870  /* Find number of lines from top to bottom of curmsg (store in savey) */
871  savey=0;
872  for (i=topmsg; i<=curmsg; i++) {
873    savey+=owl_message_get_numlines(owl_view_get_element(v, i));
874  }
875
876  /* If the direction is DOWNWARDS but we're off the bottom of the
877   *  screen, then set the topmsg to curmsg and scroll UPWARDS
878   */
879  if (direction == OWL_DIRECTION_DOWNWARDS) {
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
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
1555    /* first check if we catch the reply-lockout filter */
1556    f=owl_global_get_filter(&g, "reply-lockout");
1557    if (f) {
1558      if (owl_filter_message_match(f, m)) {
1559        owl_function_makemsg("Sorry, replies to this message have been disabled by the reply-lockout filter");
1560        return;
1561      }
1562    }
1563
1564    if (owl_message_is_direction_out(m)) {
1565      owl_function_zwrite_setup(owl_message_get_zwriteline(m));
1566      owl_global_set_buffercommand(&g, owl_message_get_zwriteline(m));
1567    } else if (owl_message_is_type_admin(m)) {
1568      owl_function_makemsg("You cannot reply to this admin message");
1569    } else {
1570      if (owl_message_is_login(m)) {
1571        class="MESSAGE";
1572        inst="PERSONAL";
1573        to=owl_message_get_sender(m);
1574      } else if (type==1) {
1575        class="MESSAGE";
1576        inst="PERSONAL";
1577        to=owl_message_get_sender(m);
1578      } else {
1579        class=owl_message_get_class(m);
1580        inst=owl_message_get_instance(m);
1581        to=owl_message_get_recipient(m);
1582        cc=owl_message_get_cc(m);
1583        if (!strcmp(to, "") || !strcmp(to, "*")) {
1584          to="";
1585        } else if (to[0]=='@') {
1586          /* leave it, to get the realm */
1587        } else {
1588          to=owl_message_get_sender(m);
1589        }
1590      }
1591     
1592      /* create the command line */
1593      buff = owl_strdup("zwrite");
1594      if (strcasecmp(class, "message")) {
1595        buff = owl_sprintf("%s -c %s%s%s", oldbuff=buff, owl_getquoting(class), class, owl_getquoting(class));
1596        owl_free(oldbuff);
1597      }
1598      if (strcasecmp(inst, "personal")) {
1599        buff = owl_sprintf("%s -i %s%s%s", oldbuff=buff, owl_getquoting(inst), inst, owl_getquoting(inst));
1600        owl_free(oldbuff);
1601      }
1602      if (*to != '\0') {
1603        char *tmp, *oldtmp;
1604        tmp=short_zuser(to);
1605        if (cc) {
1606          tmp = owl_util_uniq(oldtmp=tmp, cc, "-");
1607          owl_free(oldtmp);
1608          buff = owl_sprintf("%s -C %s", oldbuff=buff, tmp);
1609          owl_free(oldbuff);
1610        } else {
1611          tmp=short_zuser(to);
1612          buff = owl_sprintf("%s %s", oldbuff=buff, tmp);
1613          owl_free(oldbuff);
1614        }
1615        owl_free(tmp);
1616      }
1617      if (cc) owl_free(cc);
1618
1619      if (enter) {
1620        owl_history *hist = owl_global_get_cmd_history(&g);
1621        owl_history_store(hist, buff);
1622        owl_history_reset(hist);
1623        owl_function_command_norv(buff);
1624      } else {
1625        owl_function_start_command(buff);
1626      }
1627      owl_free(buff);
1628    }
1629  }
1630}
1631
1632void owl_function_zlocate(char *user, int auth) {
1633  char buff[LINE], myuser[LINE];
1634  char *ptr;
1635
1636  strcpy(myuser, user);
1637  ptr=strchr(myuser, '@');
1638  if (!ptr) {
1639    strcat(myuser, "@");
1640    strcat(myuser, ZGetRealm());
1641  }
1642
1643  owl_zephyr_zlocate(myuser, buff, auth);
1644  owl_function_popless_text(buff);
1645}
1646
1647void owl_function_start_command(char *line) {
1648  int i, j;
1649  owl_editwin *tw;
1650
1651  tw=owl_global_get_typwin(&g);
1652  owl_global_set_typwin_active(&g);
1653  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, 
1654                        owl_global_get_cmd_history(&g));
1655
1656  owl_editwin_set_locktext(tw, "command: ");
1657  owl_global_set_needrefresh(&g);
1658
1659  j=strlen(line);
1660  for (i=0; i<j; i++) {
1661    owl_editwin_process_char(tw, line[i]);
1662  }
1663  owl_editwin_redisplay(tw, 0);
1664}
1665
1666char *owl_function_exec(int argc, char **argv, char *buff, int type) {
1667  /* if type == 1 display in a popup
1668   * if type == 2 display an admin messages
1669   * if type == 0 return output
1670   * else display in a popup
1671   */
1672  char *newbuff, *redirect = " 2>&1 < /dev/null";
1673  char *out, buff2[1024];
1674  int size;
1675  FILE *p;
1676
1677  if (argc<2) {
1678    owl_function_makemsg("Wrong number of arguments to the exec command");
1679    return NULL;
1680  }
1681
1682  buff = skiptokens(buff, 1);
1683  newbuff = owl_malloc(strlen(buff)+strlen(redirect)+1);
1684  strcpy(newbuff, buff);
1685  strcat(newbuff, redirect);
1686
1687  p=popen(newbuff, "r");
1688  out=owl_malloc(1024);
1689  size=1024;
1690  strcpy(out, "");
1691  while (fgets(buff2, 1024, p)!=NULL) {
1692    size+=1024;
1693    out=owl_realloc(out, size);
1694    strcat(out, buff2);
1695  }
1696  pclose(p);
1697
1698  if (type==1) {
1699    owl_function_popless_text(out);
1700  } else if (type==0) {
1701    return out;
1702  } else if (type==2) {
1703    owl_function_adminmsg(buff, out);
1704  } else {
1705    owl_function_popless_text(out);
1706  }
1707  owl_free(out);
1708  return NULL;
1709}
1710
1711
1712char *owl_function_perl(int argc, char **argv, char *buff, int type) {
1713  /* if type == 1 display in a popup
1714   * if type == 2 display an admin messages
1715   * if type == 0 return output
1716   * else display in a popup
1717   */
1718  char *perlout;
1719
1720  if (argc<2) {
1721    owl_function_makemsg("Wrong number of arguments to perl command");
1722    return NULL;
1723  }
1724
1725  /* consume first token (argv[0]) */
1726  buff = skiptokens(buff, 1);
1727
1728  perlout = owl_config_execute(buff);
1729  if (perlout) { 
1730    if (type==1) {
1731      owl_function_popless_text(perlout);
1732    } else if (type==2) {
1733      owl_function_adminmsg(buff, perlout);
1734    } else if (type==0) {
1735      return perlout;
1736    } else {
1737      owl_function_popless_text(perlout);
1738    }
1739    owl_free(perlout);
1740  }
1741  return NULL;
1742}
1743
1744
1745void owl_function_change_view(char *filtname) {
1746  owl_view *v;
1747  owl_filter *f;
1748  int curid=-1, newpos;
1749  owl_message *curm;
1750
1751  v=owl_global_get_current_view(&g);
1752  curm=owl_view_get_element(v, owl_global_get_curmsg(&g));
1753  if (curm) {
1754    curid = owl_message_get_id(curm);
1755    owl_view_save_curmsgid(v, curid);
1756  }
1757
1758  f=owl_global_get_filter(&g, filtname);
1759  if (!f) {
1760    owl_function_makemsg("Unknown filter");
1761    return;
1762  }
1763
1764  owl_view_free(v);
1765  owl_view_create(v, f);
1766
1767  /* Figure out where to set the current message to.
1768   * - If the previous view had messages in it, go to the closest message
1769   *   to the last message in that view.
1770   * - If the previous view was empty, attempts to restore the position
1771   *   from the last time we were in that view.  */
1772  if (curm) {
1773    newpos = owl_view_get_nearest_to_msgid(v, curid);
1774  } else {
1775    newpos = owl_view_get_nearest_to_saved(v);
1776  }
1777
1778  owl_global_set_curmsg(&g, newpos);
1779
1780  owl_global_set_curmsg_vert_offset(&g, 0);
1781  owl_global_set_direction_downwards(&g);
1782  owl_function_calculate_topmsg(OWL_DIRECTION_NONE);
1783  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1784}
1785
1786void owl_function_create_filter(int argc, char **argv) {
1787  owl_filter *f;
1788  owl_view *v;
1789  int ret, inuse=0;
1790
1791  if (argc < 2) {
1792    owl_function_makemsg("Wrong number of arguments to filter command");
1793    return;
1794  }
1795
1796  v=owl_global_get_current_view(&g);
1797
1798  /* don't touch the all filter */
1799  if (!strcmp(argv[1], "all")) {
1800    owl_function_makemsg("You may not change the 'all' filter.");
1801    return;
1802  }
1803
1804  /* deal with the case of trying change the filter color */
1805  if (argc==4 && !strcmp(argv[2], "-c")) {
1806    f=owl_global_get_filter(&g, argv[1]);
1807    if (!f) {
1808      owl_function_makemsg("The filter '%s' does not exist.", argv[1]);
1809      return;
1810    }
1811    owl_filter_set_color(f, owl_util_string_to_color(argv[3]));
1812    owl_global_set_needrefresh(&g);
1813    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1814    return;
1815  }
1816
1817  /* create the filter and check for errors */
1818  f=owl_malloc(sizeof(owl_filter));
1819  ret=owl_filter_init(f, argv[1], argc-2, argv+2);
1820  if (ret==-1) {
1821    owl_free(f);
1822    owl_function_makemsg("Invalid filter syntax");
1823    return;
1824  }
1825
1826  /* if the named filter is in use by the current view, remember it */
1827  if (!strcmp(owl_view_get_filtname(v), argv[1])) {
1828    inuse=1;
1829  }
1830
1831  /* if the named filter already exists, nuke it */
1832  if (owl_global_get_filter(&g, argv[1])) {
1833    owl_global_remove_filter(&g, argv[1]);
1834  }
1835
1836  /* add the filter */
1837  owl_global_add_filter(&g, f);
1838
1839  /* if it was in use by the current view then update */
1840  if (inuse) {
1841    owl_function_change_view(argv[1]);
1842  }
1843  owl_global_set_needrefresh(&g);
1844  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1845}
1846
1847void owl_function_show_filters() {
1848  owl_list *l;
1849  owl_filter *f;
1850  int i, j;
1851  owl_fmtext fm;
1852
1853  owl_fmtext_init_null(&fm);
1854
1855  l=owl_global_get_filterlist(&g);
1856  j=owl_list_get_size(l);
1857
1858  owl_fmtext_append_bold(&fm, "Filters:\n");
1859
1860  for (i=0; i<j; i++) {
1861    f=owl_list_get_element(l, i);
1862    owl_fmtext_append_normal(&fm, "   ");
1863    if (owl_global_get_hascolors(&g)) {
1864      owl_fmtext_append_normal_color(&fm, owl_filter_get_name(f), owl_filter_get_color(f));
1865    } else {
1866      owl_fmtext_append_normal(&fm, owl_filter_get_name(f));
1867    }
1868    owl_fmtext_append_normal(&fm, "\n");
1869  }
1870  owl_function_popless_fmtext(&fm);
1871  owl_fmtext_free(&fm);
1872}
1873
1874void owl_function_show_filter(char *name) {
1875  owl_filter *f;
1876  char buff[5000];
1877
1878  f=owl_global_get_filter(&g, name);
1879  if (!f) {
1880    owl_function_makemsg("There is no filter with that name");
1881    return;
1882  }
1883  owl_filter_print(f, buff);
1884  owl_function_popless_text(buff);
1885}
1886
1887void owl_function_show_zpunts() {
1888  owl_filter *f;
1889  owl_list *fl;
1890  char buff[5000];
1891  owl_fmtext fm;
1892  int i, j;
1893
1894  owl_fmtext_init_null(&fm);
1895
1896  fl=owl_global_get_puntlist(&g);
1897  j=owl_list_get_size(fl);
1898  owl_fmtext_append_bold(&fm, "Active zpunt filters:\n");
1899
1900  for (i=0; i<j; i++) {
1901    f=owl_list_get_element(fl, i);
1902    owl_filter_print(f, buff);
1903    owl_fmtext_append_normal(&fm, buff);
1904  }
1905  owl_function_popless_fmtext(&fm);
1906  owl_fmtext_free(&fm);
1907}
1908
1909char *owl_function_fastclassinstfilt(char *class, char *instance) {
1910  /* creates a filter for a class, instance if one doesn't exist.
1911   * If instance is null then apply for all messgaes in the class.
1912   * returns the name of the filter, which the caller must free.*/
1913  owl_list *fl;
1914  owl_filter *f;
1915  char *argbuff, *filtname;
1916  int len;
1917
1918  fl=owl_global_get_filterlist(&g);
1919
1920  /* name for the filter */
1921  len=strlen(class)+30;
1922  if (instance) len+=strlen(instance);
1923  filtname=owl_malloc(len);
1924  if (!instance) {
1925    sprintf(filtname, "class-%s", class);
1926  } else {
1927    sprintf(filtname, "class-%s-instance-%s", class, instance);
1928  }
1929  downstr(filtname);
1930
1931  /* if it already exists then go with it.  This lets users override */
1932  if (owl_global_get_filter(&g, filtname)) {
1933    return filtname;
1934  }
1935
1936  /* create the new filter */
1937  argbuff=owl_malloc(len+20);
1938  sprintf(argbuff, "( class ^%s$ )", class);
1939  if (instance) {
1940    sprintf(argbuff, "%s and ( instance ^%s$ )", argbuff, instance);
1941  }
1942
1943  f=owl_malloc(sizeof(owl_filter));
1944  owl_filter_init_fromstring(f, filtname, argbuff);
1945
1946  /* add it to the global list */
1947  owl_global_add_filter(&g, f);
1948
1949  owl_free(argbuff);
1950  return filtname;
1951}
1952
1953char *owl_function_fastuserfilt(char *user) {
1954  owl_filter *f;
1955  char *argbuff, *longuser, *shortuser, *filtname;
1956
1957  /* stick the local realm on if it's not there */
1958  longuser=long_zuser(user);
1959  shortuser=short_zuser(user);
1960
1961  /* name for the filter */
1962  filtname=owl_malloc(strlen(shortuser)+20);
1963  sprintf(filtname, "user-%s", shortuser);
1964
1965  /* if it already exists then go with it.  This lets users override */
1966  if (owl_global_get_filter(&g, filtname)) {
1967    return filtname;
1968  }
1969
1970  /* create the new-internal filter */
1971  f=owl_malloc(sizeof(owl_filter));
1972
1973  argbuff=owl_malloc(strlen(longuser)+1000);
1974  sprintf(argbuff, "( type ^zephyr$ and ( class ^message$ and instance ^personal$ and ");
1975  sprintf(argbuff, "%s ( ( direction ^in$ and sender ^%s$ ) or ( direction ^out$ and recipient ^%s$ ) ) )", argbuff, longuser, longuser);
1976  sprintf(argbuff, "%s or ( ( class ^login$ ) and ( sender ^%s$ ) ) )", argbuff, longuser);
1977
1978  owl_filter_init_fromstring(f, filtname, argbuff);
1979
1980  /* add it to the global list */
1981  owl_global_add_filter(&g, f);
1982
1983  /* free stuff */
1984  owl_free(argbuff);
1985  owl_free(longuser);
1986  owl_free(shortuser);
1987
1988  return filtname;
1989}
1990
1991char *owl_function_fasttypefilt(char *type) {
1992  owl_filter *f;
1993  char *argbuff, *filtname;
1994
1995  /* name for the filter */
1996  filtname=owl_sprintf("type-%s", type);
1997
1998  /* if it already exists then go with it.  This lets users override */
1999  if (owl_global_get_filter(&g, filtname)) {
2000    return filtname;
2001  }
2002
2003  /* create the new-internal filter */
2004  f=owl_malloc(sizeof(owl_filter));
2005
2006  argbuff = owl_sprintf("type ^%s$", type);
2007
2008  owl_filter_init_fromstring(f, filtname, argbuff);
2009
2010  /* add it to the global list */
2011  owl_global_add_filter(&g, f);
2012
2013  /* free stuff */
2014  owl_free(argbuff);
2015
2016  return filtname;
2017}
2018
2019/* If flag is 1, marks for deletion.  If flag is 0,
2020 * unmarks for deletion. */
2021void owl_function_delete_curview_msgs(int flag) {
2022  owl_view *v;
2023  int i, j;
2024
2025  v=owl_global_get_current_view(&g);
2026  j=owl_view_get_size(v);
2027  for (i=0; i<j; i++) {
2028    if (flag == 1) {
2029      owl_message_mark_delete(owl_view_get_element(v, i));
2030    } else if (flag == 0) {
2031      owl_message_unmark_delete(owl_view_get_element(v, i));
2032    }
2033  }
2034
2035  owl_function_makemsg("%i messages marked for %sdeletion", j, flag?"":"un");
2036
2037  owl_mainwin_redisplay(owl_global_get_mainwin(&g)); 
2038}
2039
2040char *owl_function_smartfilter(int type) {
2041  /* Returns the name of a filter, or null.  The caller
2042   * must free this name.  */
2043  /* if the curmsg is a personal message return a filter name
2044   *    to the converstaion with that user.
2045   * If the curmsg is a class message, instance foo, recip *
2046   *    message, return a filter name to the class, inst.
2047   * If the curmsg is a class message and type==0 then
2048   *    return a filter name for just the class.
2049   * If the curmsg is a class message and type==1 then
2050   *    return a filter name for the class and instance.
2051   */
2052  owl_view *v;
2053  owl_message *m;
2054  char *zperson, *filtname=NULL;
2055 
2056  v=owl_global_get_current_view(&g);
2057  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2058
2059  if (!m || owl_view_get_size(v)==0) {
2060    owl_function_makemsg("No message selected\n");
2061    return(NULL);
2062  }
2063
2064  /* very simple handling of admin messages for now */
2065  if (owl_message_is_type_admin(m)) {
2066    return(owl_function_fasttypefilt("admin"));
2067  }
2068
2069  /* narrow personal and login messages to the sender or recip as appropriate */
2070  if (owl_message_is_personal(m) || owl_message_is_login(m)) {
2071    if (owl_message_is_type_zephyr(m)) {
2072      if (owl_message_is_direction_in(m)) {
2073        zperson=short_zuser(owl_message_get_sender(m));
2074      } else {
2075        zperson=short_zuser(owl_message_get_recipient(m));
2076      }
2077      filtname=owl_function_fastuserfilt(zperson);
2078      owl_free(zperson);
2079      return(filtname);
2080    }
2081    return(NULL);
2082  }
2083
2084  /* narrow class MESSAGE, instance foo, recip * messages to class, inst */
2085  if (!strcasecmp(owl_message_get_class(m), "message") &&
2086      !owl_message_is_personal(m)) {
2087    filtname=owl_function_fastclassinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2088    return(filtname);
2089  }
2090
2091  /* otherwise narrow to the class */
2092  if (type==0) {
2093    filtname=owl_function_fastclassinstfilt(owl_message_get_class(m), NULL);
2094  } else if (type==1) {
2095    filtname=owl_function_fastclassinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2096  }
2097  return(filtname);
2098}
2099
2100void owl_function_smartzpunt(int type) {
2101  /* Starts a zpunt command based on the current class,instance pair.
2102   * If type=0, uses just class.  If type=1, uses instance as well. */
2103  owl_view *v;
2104  owl_message *m;
2105  char *cmd, *cmdprefix, *mclass, *minst;
2106 
2107  v=owl_global_get_current_view(&g);
2108  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2109
2110  if (!m || owl_view_get_size(v)==0) {
2111    owl_function_makemsg("No message selected\n");
2112    return;
2113  }
2114
2115  /* for now we skip admin messages. */
2116  if (owl_message_is_type_admin(m)
2117      || owl_message_is_login(m)
2118      || !owl_message_is_type_zephyr(m)) {
2119    owl_function_makemsg("smartzpunt doesn't support this message type.");
2120    return;
2121  }
2122
2123  mclass = owl_message_get_class(m);
2124  minst = owl_message_get_instance(m);
2125  if (!mclass || !*mclass || *mclass==' '
2126      || (!strcasecmp(mclass, "message") && !strcasecmp(minst, "personal"))
2127      || (type && (!minst || !*minst|| *minst==' '))) {
2128    owl_function_makemsg("smartzpunt can't safely do this for <%s,%s>",
2129                         mclass, minst);
2130  } else {
2131    cmdprefix = "start-command zpunt ";
2132    cmd = owl_malloc(strlen(cmdprefix)+strlen(mclass)+strlen(minst)+3);
2133    strcpy(cmd, cmdprefix);
2134    strcat(cmd, mclass);
2135    if (type) {
2136      strcat(cmd, " ");
2137      strcat(cmd, minst);
2138    } else {
2139      strcat(cmd, " *");
2140    }
2141    owl_function_command(cmd);
2142    owl_free(cmd);
2143  }
2144}
2145
2146
2147
2148void owl_function_color_current_filter(char *color) {
2149  owl_filter *f;
2150  char *name;
2151
2152  name=owl_view_get_filtname(owl_global_get_current_view(&g));
2153  f=owl_global_get_filter(&g, name);
2154  if (!f) {
2155    owl_function_makemsg("Unknown filter");
2156    return;
2157  }
2158
2159  /* don't touch the all filter */
2160  if (!strcmp(name, "all")) {
2161    owl_function_makemsg("You may not change the 'all' filter.");
2162    return;
2163  }
2164
2165  /* deal with the case of trying change the filter color */
2166  owl_filter_set_color(f, owl_util_string_to_color(color));
2167  owl_global_set_needrefresh(&g);
2168  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2169}
2170
2171void owl_function_show_colors() {
2172  owl_fmtext fm;
2173
2174  owl_fmtext_init_null(&fm);
2175  owl_fmtext_append_normal_color(&fm, "default\n", OWL_COLOR_DEFAULT);
2176  owl_fmtext_append_normal_color(&fm, "red\n", OWL_COLOR_RED);
2177  owl_fmtext_append_normal_color(&fm, "green\n", OWL_COLOR_GREEN);
2178  owl_fmtext_append_normal_color(&fm, "yellow\n", OWL_COLOR_YELLOW);
2179  owl_fmtext_append_normal_color(&fm, "blue\n", OWL_COLOR_BLUE);
2180  owl_fmtext_append_normal_color(&fm, "magenta\n", OWL_COLOR_MAGENTA);
2181  owl_fmtext_append_normal_color(&fm, "cyan\n", OWL_COLOR_CYAN);
2182  owl_fmtext_append_normal_color(&fm, "white\n", OWL_COLOR_WHITE);
2183
2184  owl_function_popless_fmtext(&fm);
2185  owl_fmtext_free(&fm);
2186}
2187
2188void owl_function_zpunt(char *class, char *inst, char *recip, int direction) {
2189  /* add the given class, inst, recip to the punt list for filtering.
2190   *   if direction==0 then punt
2191   *   if direction==1 then unpunt */
2192  owl_filter *f;
2193  owl_list *fl;
2194  char *buff;
2195  int ret, i, j;
2196
2197  fl=owl_global_get_puntlist(&g);
2198
2199  /* first, create the filter */
2200  f=malloc(sizeof(owl_filter));
2201  buff=malloc(strlen(class)+strlen(inst)+strlen(recip)+100);
2202  if (!strcmp(recip, "*")) {
2203    sprintf(buff, "class ^%s$ and instance ^%s$", class, inst);
2204  } else {
2205    sprintf(buff, "class ^%s$ and instance ^%s$ and recipient %s", class, inst, recip);
2206  }
2207  owl_function_debugmsg("About to filter %s", buff);
2208  ret=owl_filter_init_fromstring(f, "punt-filter", buff);
2209  owl_free(buff);
2210  if (ret) {
2211    owl_function_makemsg("Error creating filter for zpunt");
2212    owl_filter_free(f);
2213    return;
2214  }
2215
2216  /* Check for an identical filter */
2217  j=owl_list_get_size(fl);
2218  for (i=0; i<j; i++) {
2219    if (owl_filter_equiv(f, owl_list_get_element(fl, i))) {
2220      /* if we're punting, then just silently bow out on this duplicate */
2221      if (direction==0) {
2222        owl_filter_free(f);
2223        return;
2224      }
2225
2226      /* if we're unpunting, then remove this filter from the puntlist */
2227      if (direction==1) {
2228        owl_filter_free(owl_list_get_element(fl, i));
2229        owl_list_remove_element(fl, i);
2230        return;
2231      }
2232    }
2233  }
2234
2235  /* If we're punting, add the filter to the global punt list */
2236  if (direction==0) {
2237    owl_list_append_element(fl, f);
2238  }
2239}
2240
2241void owl_function_activate_keymap(char *keymap) {
2242  if (!owl_keyhandler_activate(owl_global_get_keyhandler(&g), keymap)) {
2243    owl_function_makemsg("Unable to activate keymap '%s'", keymap);
2244  }
2245}
2246
2247
2248void owl_function_show_keymaps() {
2249  owl_list l;
2250  owl_fmtext fm;
2251  owl_keymap *km;
2252  owl_keyhandler *kh;
2253  int i, numkm;
2254  char *kmname;
2255
2256  kh = owl_global_get_keyhandler(&g);
2257  owl_fmtext_init_null(&fm);
2258  owl_fmtext_append_bold(&fm, "Keymaps:   ");
2259  owl_fmtext_append_normal(&fm, "(use 'show keymap <name>' for details)\n");
2260  owl_keyhandler_get_keymap_names(kh, &l);
2261  owl_fmtext_append_list(&fm, &l, "\n", owl_function_keymap_summary);
2262  owl_fmtext_append_normal(&fm, "\n");
2263
2264  numkm = owl_list_get_size(&l);
2265  for (i=0; i<numkm; i++) {
2266    kmname = owl_list_get_element(&l, i);
2267    km = owl_keyhandler_get_keymap(kh, kmname);
2268    owl_fmtext_append_bold(&fm, "\n\n----------------------------------------------------------------------------------------------------\n\n");
2269    owl_keymap_get_details(km, &fm);   
2270  }
2271  owl_fmtext_append_normal(&fm, "\n");
2272 
2273  owl_function_popless_fmtext(&fm);
2274  owl_keyhandler_keymap_namelist_free(&l);
2275  owl_fmtext_free(&fm);
2276}
2277
2278char *owl_function_keymap_summary(void *name) {
2279  owl_keymap *km
2280    = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
2281  if (km) return owl_keymap_summary(km);
2282  else return(NULL);
2283}
2284
2285/* TODO: implement for real */
2286void owl_function_show_keymap(char *name) {
2287  owl_fmtext fm;
2288  owl_keymap *km;
2289
2290  owl_fmtext_init_null(&fm);
2291  km = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
2292  if (km) {
2293    owl_keymap_get_details(km, &fm);
2294  } else {
2295    owl_fmtext_append_normal(&fm, "No such keymap...\n");
2296  } 
2297  owl_function_popless_fmtext(&fm);
2298  owl_fmtext_free(&fm);
2299}
2300
2301void owl_function_help_for_command(char *cmdname) {
2302  owl_fmtext fm;
2303
2304  owl_fmtext_init_null(&fm);
2305  owl_cmd_get_help(owl_global_get_cmddict(&g), cmdname, &fm);
2306  owl_function_popless_fmtext(&fm); 
2307  owl_fmtext_free(&fm);
2308}
2309
2310void owl_function_search_start(char *string, int direction) {
2311  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
2312  owl_global_set_search_active(&g, string);
2313  owl_function_search_helper(0, direction);
2314}
2315
2316void owl_function_search_continue(int direction) {
2317  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
2318  owl_function_search_helper(1, direction);
2319}
2320
2321void owl_function_search_helper(int mode, int direction) {
2322  /* move to a message that contains the string.  If direction is
2323   * OWL_DIRECTION_DOWNWARDS then search fowards, if direction is
2324   * OWL_DIRECTION_UPWARDS then search backwards.
2325   *
2326   * If mode==0 then it will stay on the current message if it
2327   * contains the string.
2328   */
2329
2330  owl_view *v;
2331  int viewsize, i, curmsg, start;
2332  owl_message *m;
2333
2334  v=owl_global_get_current_view(&g);
2335  viewsize=owl_view_get_size(v);
2336  curmsg=owl_global_get_curmsg(&g);
2337 
2338  if (viewsize==0) {
2339    owl_function_makemsg("No messages present");
2340    return;
2341  }
2342
2343  if (mode==0) {
2344    start=curmsg;
2345  } else if (direction==OWL_DIRECTION_DOWNWARDS) {
2346    start=curmsg+1;
2347  } else {
2348    start=curmsg-1;
2349  }
2350
2351  /* bounds check */
2352  if (start>=viewsize || start<0) {
2353    owl_function_makemsg("No further matches found");
2354    return;
2355  }
2356
2357  for (i=start; i<viewsize && i>=0;) {
2358    m=owl_view_get_element(v, i);
2359    if (owl_message_search(m, owl_global_get_search_string(&g))) {
2360      owl_global_set_curmsg(&g, i);
2361      owl_function_calculate_topmsg(direction);
2362      owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2363      if (direction==OWL_DIRECTION_DOWNWARDS) {
2364        owl_global_set_direction_downwards(&g);
2365      } else {
2366        owl_global_set_direction_upwards(&g);
2367      }
2368      return;
2369    }
2370    if (direction==OWL_DIRECTION_DOWNWARDS) {
2371      i++;
2372    } else {
2373      i--;
2374    }
2375  }
2376  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2377  owl_function_makemsg("No matches found");
2378}
2379
2380
2381/* strips formatting from ztext and returns the unformatted text.
2382 * caller is responsible for freeing. */
2383char *owl_function_ztext_stylestrip(char *zt) {
2384  owl_fmtext fm;
2385  char *plaintext;
2386
2387  owl_fmtext_init_null(&fm);
2388  owl_fmtext_append_ztext(&fm, zt);
2389  plaintext = owl_fmtext_print_plain(&fm);
2390  owl_fmtext_free(&fm);
2391  return(plaintext);
2392}
Note: See TracBrowser for help on using the repository browser.