source: functions.c @ 88736cb

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