source: functions.c @ 5eeea3b

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