source: functions.c @ 8fec514

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