source: functions.c @ f1e629d

barnowl_perlaimdebianowlrelease-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since f1e629d was f1e629d, checked in by Erik Nygren <nygren@mit.edu>, 18 years ago
New API for perl message formatting functions. Legacy variables are still supported for owl::format_msg and owl::receive_msg, but these functions are now also passed an owl::Message object which contains methods for accessing the contents of the message. See perlwrap.pm (and docs TBD) for the available methods. *** WARNING: The exact API for owl::Message has *** not yet stabilized. Added "style" command for creating new styles. Usage: style <name> perl <function_name> Added support for "show styles". Changed global style table from list to dictionary. Changed AIM password prompt from "Password:" to "AIM Password:". Messages are reformatted after a window resize to allow styles to take into account the width of the window. When perl throws an error, the message is put in the msgwin if possible. Added perl functions for: owl::getcurmsg() -- returns an owl::Message object for the active message in the current view. owl::getnumcols() -- returns the column width of the window owl::zephyr_getrealm() -- returns the zephyr realm owl::zephyr_getsender() -- returns the zephyr sender Made owl::COMMAND("foo"); be syntactic sugar for owl::command("COMMAND foo"); *** Is this a good or bad idea? *** This feature may be taken out before release. Added perlwrap.pm to contain perl code to be compiled into the binary. This is transformed into perlwrap.c by encapsulate.pl. Renamed readconfig.c to perlconfig.c and changed variables accordingly. Minor bugfixes in cmd.c and commands.c
  • Property mode set to 100644
File size: 83.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 <time.h>
7#include <sys/types.h>
8#include <sys/stat.h>
9#include <sys/wait.h>
10#include <errno.h>
11#include <signal.h>
12#include "owl.h"
13
14static const char fileIdent[] = "$Id$";
15
16void owl_function_noop(void)
17{
18  return;
19}
20
21char *owl_function_command(char *cmdbuff)
22{
23  owl_function_debugmsg("executing command: %s", cmdbuff);
24  return owl_cmddict_execute(owl_global_get_cmddict(&g), 
25                             owl_global_get_context(&g), cmdbuff);
26}
27
28void owl_function_command_norv(char *cmdbuff)
29{
30  char *rv;
31  rv=owl_function_command(cmdbuff);
32  if (rv) owl_free(rv);
33}
34
35void owl_function_command_alias(char *alias_from, char *alias_to)
36{
37  owl_cmddict_add_alias(owl_global_get_cmddict(&g), alias_from, alias_to);
38}
39
40owl_cmd *owl_function_get_cmd(char *name)
41{
42  return owl_cmddict_find(owl_global_get_cmddict(&g), name);
43}
44
45void owl_function_show_commands()
46{
47  owl_list l;
48  owl_fmtext fm;
49
50  owl_fmtext_init_null(&fm);
51  owl_fmtext_append_bold(&fm, "Commands:  ");
52  owl_fmtext_append_normal(&fm, "(use 'show command <name>' for details)\n");
53  owl_cmddict_get_names(owl_global_get_cmddict(&g), &l);
54  owl_fmtext_append_list(&fm, &l, "\n", owl_function_cmd_describe);
55  owl_fmtext_append_normal(&fm, "\n");
56  owl_function_popless_fmtext(&fm);
57  owl_cmddict_namelist_free(&l);
58  owl_fmtext_free(&fm);
59}
60
61
62void owl_function_show_view(char *viewname)
63{
64  owl_view *v;
65  owl_fmtext fm;
66
67  /* we only have the one view right now */
68  v=owl_global_get_current_view(&g);
69  if (viewname && strcmp(viewname, owl_view_get_name(v))) {
70    owl_function_makemsg("No view named '%s'", viewname);
71    return;
72  }
73
74  owl_fmtext_init_null(&fm);
75  owl_view_to_fmtext(v, &fm);
76  owl_function_popless_fmtext(&fm);
77  owl_fmtext_free(&fm);
78}
79
80void owl_function_show_styles() {
81  owl_list l;
82  owl_fmtext fm;
83
84  owl_fmtext_init_null(&fm);
85  owl_fmtext_append_bold(&fm, "Styles:\n");
86  owl_global_get_style_names(&g, &l);
87  owl_fmtext_append_list(&fm, &l, "\n", owl_function_style_describe);
88  owl_fmtext_append_normal(&fm, "\n");
89  owl_function_popless_fmtext(&fm);
90  owl_list_free_all(&l, owl_free);
91  owl_fmtext_free(&fm);
92}
93
94char *owl_function_style_describe(void *name) {
95  char *desc, *s;
96  owl_style *style;
97  style = owl_global_get_style_by_name(&g, name);
98  if (style) {
99    desc = owl_style_get_description(style);
100  } else {
101    desc = "???";
102  }
103  s = owl_sprintf("%-20s - %s%s", name, 
104                  0==owl_style_validate(style)?"":"[INVALID] ",
105                  desc);
106  return s;
107}
108
109char *owl_function_cmd_describe(void *name)
110{
111  owl_cmd *cmd = owl_cmddict_find(owl_global_get_cmddict(&g), name);
112  if (cmd) return owl_cmd_describe(cmd);
113  else return(NULL);
114}
115
116void owl_function_show_command(char *name)
117{
118  owl_function_help_for_command(name);
119}
120
121void owl_function_adminmsg(char *header, char *body)
122{
123  owl_message *m;
124  int followlast;
125
126  followlast=owl_global_should_followlast(&g);
127  m=owl_malloc(sizeof(owl_message));
128  owl_message_create_admin(m, header, body);
129  owl_messagelist_append_element(owl_global_get_msglist(&g), m);
130  owl_view_consider_message(owl_global_get_current_view(&g), m);
131
132  if (followlast) owl_function_lastmsg_noredisplay();
133
134  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
135  if (owl_popwin_is_active(owl_global_get_popwin(&g))) {
136    owl_popwin_refresh(owl_global_get_popwin(&g));
137  }
138 
139  wnoutrefresh(owl_global_get_curs_recwin(&g));
140  owl_global_set_needrefresh(&g);
141}
142
143void owl_function_make_outgoing_zephyr(char *body, char *zwriteline, char *zsig)
144{
145  owl_message *m;
146  int followlast;
147  owl_zwrite z;
148 
149  followlast=owl_global_should_followlast(&g);
150
151  /* create a zwrite for the purpose of filling in other message fields */
152  owl_zwrite_create_from_line(&z, zwriteline);
153
154  /* create the message */
155  m=owl_malloc(sizeof(owl_message));
156  owl_message_create_from_zwriteline(m, zwriteline, body, zsig);
157
158  /* add it to the global list and current view */
159  owl_messagelist_append_element(owl_global_get_msglist(&g), m);
160  owl_view_consider_message(owl_global_get_current_view(&g), m);
161
162  if (followlast) owl_function_lastmsg_noredisplay();
163
164  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
165  if (owl_popwin_is_active(owl_global_get_popwin(&g))) {
166    owl_popwin_refresh(owl_global_get_popwin(&g));
167  }
168 
169  wnoutrefresh(owl_global_get_curs_recwin(&g));
170  owl_global_set_needrefresh(&g);
171  owl_zwrite_free(&z);
172}
173
174int owl_function_make_outgoing_aim(char *body, char *to)
175{
176  owl_message *m;
177  int followlast;
178
179
180  if (!owl_global_is_aimloggedin(&g)) {
181    return(-1);
182  }
183 
184  followlast=owl_global_should_followlast(&g);
185
186  /* create the message */
187  m=owl_malloc(sizeof(owl_message));
188  owl_message_create_aim(m,
189                         owl_global_get_aim_screenname(&g),
190                         to,
191                         body,
192                         OWL_MESSAGE_DIRECTION_OUT,
193                         0);
194
195  /* add it to the global list and current view */
196  owl_messagelist_append_element(owl_global_get_msglist(&g), m);
197  owl_view_consider_message(owl_global_get_current_view(&g), m);
198
199  if (followlast) owl_function_lastmsg_noredisplay();
200
201  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
202  if (owl_popwin_is_active(owl_global_get_popwin(&g))) {
203    owl_popwin_refresh(owl_global_get_popwin(&g));
204  }
205 
206  wnoutrefresh(owl_global_get_curs_recwin(&g));
207  owl_global_set_needrefresh(&g);
208  return(0);
209}
210
211void owl_function_zwrite_setup(char *line)
212{
213  owl_editwin *e;
214  char buff[1024];
215  owl_zwrite z;
216  int ret;
217
218  /* check the arguments */
219  ret=owl_zwrite_create_from_line(&z, line);
220  if (ret) {
221    owl_function_makemsg("Error in zwrite arugments");
222    owl_zwrite_free(&z);
223    return;
224  }
225
226  /* send a ping if necessary */
227  if (owl_global_is_txping(&g)) {
228    owl_zwrite_send_ping(&z);
229  }
230  owl_zwrite_free(&z);
231
232  /* create and setup the editwin */
233  e=owl_global_get_typwin(&g);
234  owl_editwin_new_style(e, OWL_EDITWIN_STYLE_MULTILINE, owl_global_get_msg_history(&g));
235
236  if (!owl_global_get_lockout_ctrld(&g)) {
237    owl_function_makemsg("Type your zephyr below.  End with ^D or a dot on a line by itself.  ^C will quit.");
238  } else {
239    owl_function_makemsg("Type your zephyr below.  End with a dot on a line by itself.  ^C will quit.");
240  }
241
242  owl_editwin_clear(e);
243  owl_editwin_set_dotsend(e);
244  strcpy(buff, "----> ");
245  strcat(buff, line);
246  strcat(buff, "\n");
247  owl_editwin_set_locktext(e, buff);
248
249  /* make it active */
250  owl_global_set_typwin_active(&g);
251
252  owl_global_set_buffercommand(&g, line);
253}
254
255void owl_function_aimwrite_setup(char *line)
256{
257  owl_editwin *e;
258  char buff[1024];
259
260  /* check the arguments */
261
262  /* create and setup the editwin */
263  e=owl_global_get_typwin(&g);
264  owl_editwin_new_style(e, OWL_EDITWIN_STYLE_MULTILINE, owl_global_get_msg_history(&g));
265
266  if (!owl_global_get_lockout_ctrld(&g)) {
267    owl_function_makemsg("Type your message below.  End with ^D or a dot on a line by itself.  ^C will quit.");
268  } else {
269    owl_function_makemsg("Type your message below.  End with a dot on a line by itself.  ^C will quit.");
270  }
271
272  owl_editwin_clear(e);
273  owl_editwin_set_dotsend(e);
274  strcpy(buff, "----> ");
275  strcat(buff, line);
276  strcat(buff, "\n");
277  owl_editwin_set_locktext(e, buff);
278
279  /* make it active */
280  owl_global_set_typwin_active(&g);
281
282  owl_global_set_buffercommand(&g, line);
283}
284
285/* send, log and display an outgoing zephyr.  If 'msg' is NULL
286 * the message is expected to be set from the zwrite line itself
287 */
288void owl_function_zwrite(char *line, char *msg)
289{
290  owl_zwrite z;
291  int i, j;
292  char *mymsg;
293
294  /* create the zwrite and send the message */
295  owl_zwrite_create_from_line(&z, line);
296  if (msg) {
297    owl_zwrite_set_message(&z, msg);
298  }
299
300  owl_zwrite_send_message(&z);
301  owl_function_makemsg("Waiting for ack...");
302
303  mymsg=owl_zwrite_get_message(&z);
304
305  /* display the message as an outgoing message in the receive window */
306  if (owl_global_is_displayoutgoing(&g) && owl_zwrite_is_personal(&z)) {
307    owl_function_make_outgoing_zephyr(mymsg, line, owl_zwrite_get_zsig(&z));
308  }
309
310  /* log it if we have logging turned on */
311  if (owl_global_is_logging(&g) && owl_zwrite_is_personal(&z)) {
312    j=owl_zwrite_get_numrecips(&z);
313    for (i=0; i<j; i++) {
314      owl_log_outgoing_zephyr(owl_zwrite_get_recip_n(&z, i), mymsg);
315    }
316  }
317
318  /* free the zwrite */
319  owl_zwrite_free(&z);
320}
321
322/* send, log and display an outgoing zcrypt zephyr.  If 'msg' is NULL
323 * the message is expected to be set from the zwrite line itself
324 */
325void owl_function_zcrypt(char *line, char *msg)
326{
327  owl_zwrite z;
328  int i, j, ret;
329  char *mymsg;
330  char *cryptmsg;
331
332  /* create the zwrite and send the message */
333  owl_zwrite_create_from_line(&z, line);
334  if (msg) {
335    owl_zwrite_set_message(&z, msg);
336  }
337
338  mymsg=owl_zwrite_get_message(&z);
339#ifdef OWL_ENABLE_ZCRYPT
340  cryptmsg=owl_malloc(strlen(mymsg)*4);
341  ret=owl_zcrypt_encrypt(cryptmsg, mymsg, owl_zwrite_get_class(&z), owl_zwrite_get_instance(&z));
342  if (ret) {
343    owl_function_makemsg("Error in zcrypt, possibly no key found.  Message not sent.");
344    owl_function_beep();
345    owl_free(cryptmsg);
346    return;
347  }
348#else
349  cryptmsg=owl_strdup(mymsg);
350#endif
351
352  owl_zwrite_set_message(&z, cryptmsg);
353  owl_zwrite_set_opcode(&z, "crypt");
354  mymsg=cryptmsg;
355   
356  owl_zwrite_send_message(&z);
357  owl_function_makemsg("Waiting for ack...");
358
359  /* display the message as an outgoing message in the receive window */
360  if (owl_global_is_displayoutgoing(&g) && owl_zwrite_is_personal(&z)) {
361    owl_function_make_outgoing_zephyr(mymsg, line, owl_zwrite_get_zsig(&z));
362  }
363
364  /* log it if we have logging turned on */
365  if (owl_global_is_logging(&g) && owl_zwrite_is_personal(&z)) {
366    j=owl_zwrite_get_numrecips(&z);
367    for (i=0; i<j; i++) {
368      owl_log_outgoing_zephyr(owl_zwrite_get_recip_n(&z, i), mymsg);
369    }
370  }
371
372  /* free the zwrite */
373  owl_free(cryptmsg);
374  owl_zwrite_free(&z);
375}
376
377
378void owl_function_aimwrite(char *to)
379{
380  /*  send the message */
381  owl_aim_send_im(to, owl_editwin_get_text(owl_global_get_typwin(&g)));
382  owl_function_makemsg("AIM message sent.");
383
384  /* display the message as an outgoing message in the receive window */
385  if (owl_global_is_displayoutgoing(&g)) {
386    owl_function_make_outgoing_aim(owl_editwin_get_text(owl_global_get_typwin(&g)), to);
387  }
388
389  /* log it if we have logging turned on */
390  if (owl_global_is_logging(&g)) {
391    owl_log_outgoing_aim(to, owl_editwin_get_text(owl_global_get_typwin(&g)));
392  }
393}
394
395
396
397/* If filter is non-null, looks for the next message matching
398 * that filter.  If skip_deleted, skips any deleted messages.
399 * If last_if_none, will stop at the last message in the view
400 * if no matching messages are found.  */
401void owl_function_nextmsg_full(char *filter, int skip_deleted, int last_if_none)
402{
403  int curmsg, i, viewsize, found;
404  owl_view *v;
405  owl_filter *f = NULL;
406  owl_message *m;
407
408  v=owl_global_get_current_view(&g);
409
410  if (filter) {
411    f=owl_global_get_filter(&g, filter);
412    if (!f) {
413      owl_function_makemsg("No %s filter defined", filter);
414      return;
415    }
416  }
417
418  curmsg=owl_global_get_curmsg(&g);
419  viewsize=owl_view_get_size(v);
420  found=0;
421
422  /* just check to make sure we're in bounds... */
423  if (curmsg>viewsize-1) curmsg=viewsize-1;
424  if (curmsg<0) curmsg=0;
425
426  for (i=curmsg+1; i<viewsize; i++) {
427    m=owl_view_get_element(v, i);
428    if (skip_deleted && owl_message_is_delete(m)) continue;
429    if (f && !owl_filter_message_match(f, m)) continue;
430    found = 1;
431    break;
432  }
433
434  if (i>owl_view_get_size(v)-1) i=owl_view_get_size(v)-1;
435
436  if (!found) {
437    owl_function_makemsg("already at last%s message%s%s",
438                         skip_deleted?" non-deleted":"",
439                         filter?" in ":"", filter?filter:"");
440    /* if (!skip_deleted) owl_function_beep(); */
441  }
442
443  if (last_if_none || found) {
444    owl_global_set_curmsg(&g, i);
445    owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
446    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
447    owl_global_set_direction_downwards(&g);
448  }
449}
450
451void owl_function_prevmsg_full(char *filter, int skip_deleted, int first_if_none)
452{
453  int curmsg, i, viewsize, found;
454  owl_view *v;
455  owl_filter *f = NULL;
456  owl_message *m;
457
458  v=owl_global_get_current_view(&g);
459
460  if (filter) {
461    f=owl_global_get_filter(&g, filter);
462    if (!f) {
463      owl_function_makemsg("No %s filter defined", filter);
464      return;
465    }
466  }
467
468  curmsg=owl_global_get_curmsg(&g);
469  viewsize=owl_view_get_size(v);
470  found=0;
471
472  /* just check to make sure we're in bounds... */
473  if (curmsg<0) curmsg=0;
474
475  for (i=curmsg-1; i>=0; i--) {
476    m=owl_view_get_element(v, i);
477    if (skip_deleted && owl_message_is_delete(m)) continue;
478    if (f && !owl_filter_message_match(f, m)) continue;
479    found = 1;
480    break;
481  }
482
483  if (i<0) i=0;
484
485  if (!found) {
486    owl_function_makemsg("already at first%s message%s%s",
487                         skip_deleted?" non-deleted":"",
488                         filter?" in ":"", filter?filter:"");
489    /* if (!skip_deleted) owl_function_beep(); */
490  }
491
492  if (first_if_none || found) {
493    owl_global_set_curmsg(&g, i);
494    owl_function_calculate_topmsg(OWL_DIRECTION_UPWARDS);
495    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
496    owl_global_set_direction_upwards(&g);
497  }
498}
499
500void owl_function_nextmsg()
501{
502  owl_function_nextmsg_full(NULL, 0, 1);
503}
504
505
506void owl_function_prevmsg()
507{
508  owl_function_prevmsg_full(NULL, 0, 1);
509}
510
511void owl_function_nextmsg_notdeleted()
512{
513  owl_function_nextmsg_full(NULL, 1, 1);
514}
515
516void owl_function_prevmsg_notdeleted()
517{
518  owl_function_prevmsg_full(NULL, 1, 1);
519}
520
521
522void owl_function_nextmsg_personal()
523{
524  owl_function_nextmsg_full("personal", 0, 0);
525}
526
527void owl_function_prevmsg_personal()
528{
529  owl_function_prevmsg_full("personal", 0, 0);
530}
531
532
533/* if move_after is 1, moves after the delete */
534void owl_function_deletecur(int move_after)
535{
536  int curmsg;
537  owl_view *v;
538
539  v=owl_global_get_current_view(&g);
540
541  /* bail if there's no current message */
542  if (owl_view_get_size(v) < 1) {
543    owl_function_makemsg("No current message to delete");
544    return;
545  }
546
547  /* mark the message for deletion */
548  curmsg=owl_global_get_curmsg(&g);
549  owl_view_delete_element(v, curmsg);
550
551  if (move_after) {
552    /* move the poiner in the appropriate direction
553     * to the next undeleted msg */
554    if (owl_global_get_direction(&g)==OWL_DIRECTION_UPWARDS) {
555      owl_function_prevmsg_notdeleted();
556    } else {
557      owl_function_nextmsg_notdeleted();
558    }
559  }
560}
561
562
563void owl_function_undeletecur(int move_after)
564{
565  int curmsg;
566  owl_view *v;
567
568  v=owl_global_get_current_view(&g);
569 
570  if (owl_view_get_size(v) < 1) {
571    owl_function_makemsg("No current message to undelete");
572    return;
573  }
574  curmsg=owl_global_get_curmsg(&g);
575
576  owl_view_undelete_element(v, curmsg);
577
578  if (move_after) {
579    if (owl_global_get_direction(&g)==OWL_DIRECTION_UPWARDS) {
580      if (curmsg>0) {
581        owl_function_prevmsg();
582      } else {
583        owl_function_nextmsg();
584      }
585    } else {
586      owl_function_nextmsg();
587    }
588  }
589
590  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
591}
592
593
594void owl_function_expunge()
595{
596  int curmsg;
597  owl_message *m;
598  owl_messagelist *ml;
599  owl_view *v;
600  int lastmsgid=0;
601
602  curmsg=owl_global_get_curmsg(&g);
603  v=owl_global_get_current_view(&g);
604  ml=owl_global_get_msglist(&g);
605
606  m=owl_view_get_element(v, curmsg);
607  if (m) lastmsgid = owl_message_get_id(m);
608
609  /* expunge the message list */
610  owl_messagelist_expunge(ml);
611
612  /* update all views (we only have one right now) */
613  owl_view_recalculate(v);
614
615  /* find where the new position should be
616     (as close as possible to where we last where) */
617  curmsg = owl_view_get_nearest_to_msgid(v, lastmsgid);
618  if (curmsg>owl_view_get_size(v)-1) curmsg = owl_view_get_size(v)-1;
619  if (curmsg<0) curmsg = 0;
620  owl_global_set_curmsg(&g, curmsg);
621  owl_function_calculate_topmsg(OWL_DIRECTION_NONE);
622  /* if there are no messages set the direction to down in case we
623     delete everything upwards */
624  owl_global_set_direction_downwards(&g);
625 
626  owl_function_makemsg("Messages expunged");
627  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
628}
629
630
631void owl_function_firstmsg()
632{
633  owl_global_set_curmsg(&g, 0);
634  owl_global_set_topmsg(&g, 0);
635  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
636  owl_global_set_direction_downwards(&g);
637}
638
639void owl_function_lastmsg_noredisplay()
640{
641  int oldcurmsg, curmsg;
642  owl_view *v;
643
644  v=owl_global_get_current_view(&g);
645  oldcurmsg=owl_global_get_curmsg(&g);
646  curmsg=owl_view_get_size(v)-1; 
647  if (curmsg<0) curmsg=0;
648  owl_global_set_curmsg(&g, curmsg);
649  if (oldcurmsg < curmsg) {
650    owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
651  } else if (curmsg<owl_view_get_size(v)) {
652    /* If already at the end, blank the screen and move curmsg
653     * past the end of the messages. */
654    owl_global_set_topmsg(&g, curmsg+1);
655    owl_global_set_curmsg(&g, curmsg+1);
656  } 
657  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
658  owl_global_set_direction_downwards(&g);
659}
660
661void owl_function_lastmsg()
662{
663  owl_function_lastmsg_noredisplay();
664  owl_mainwin_redisplay(owl_global_get_mainwin(&g)); 
665}
666
667void owl_function_shift_right()
668{
669  owl_global_set_rightshift(&g, owl_global_get_rightshift(&g)+10);
670  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
671  owl_global_set_needrefresh(&g);
672}
673
674
675void owl_function_shift_left()
676{
677  int shift;
678
679  shift=owl_global_get_rightshift(&g);
680  if (shift>=10) {
681    owl_global_set_rightshift(&g, shift-10);
682    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
683    owl_global_set_needrefresh(&g);
684  } else {
685    owl_function_beep();
686    owl_function_makemsg("Already full left");
687  }
688}
689
690
691void owl_function_unsuball()
692{
693  unsuball();
694  owl_function_makemsg("Unsubscribed from all messages.");
695}
696
697void owl_function_loadsubs(char *file)
698{
699  int ret;
700
701  ret=owl_zephyr_loadsubs(file);
702
703  if (!owl_context_is_interactive(owl_global_get_context(&g))) return;
704  if (ret==0) {
705    owl_function_makemsg("Subscribed to messages from file.");
706  } else if (ret==-1) {
707    owl_function_makemsg("Could not open file.");
708  } else {
709    owl_function_makemsg("Error subscribing to messages from file.");
710  }
711}
712
713void owl_function_loadloginsubs(char *file)
714{
715  int ret;
716
717  ret=owl_zephyr_loadloginsubs(file);
718
719  if (!owl_context_is_interactive(owl_global_get_context(&g))) return;
720  if (ret==0) {
721    owl_function_makemsg("Subscribed to login messages from file.");
722  } else if (ret==-1) {
723    owl_function_makemsg("Could not open file for login subscriptions.");
724  } else {
725    owl_function_makemsg("Error subscribing to login messages from file.");
726  }
727}
728
729void owl_function_suspend()
730{
731  endwin();
732  printf("\n");
733  kill(getpid(), SIGSTOP);
734
735  /* resize to reinitialize all the windows when we come back */
736  owl_command_resize();
737}
738
739void owl_function_zaway_toggle()
740{
741  if (!owl_global_is_zaway(&g)) {
742    owl_global_set_zaway_msg(&g, owl_global_get_zaway_msg_default(&g));
743    owl_function_zaway_on();
744  } else {
745    owl_function_zaway_off();
746  }
747}
748
749void owl_function_zaway_on()
750{
751  owl_global_set_zaway_on(&g);
752  owl_function_makemsg("zaway set (%s)", owl_global_get_zaway_msg(&g));
753}
754
755void owl_function_zaway_off()
756{
757  owl_global_set_zaway_off(&g);
758  owl_function_makemsg("zaway off");
759}
760
761void owl_function_quit()
762{
763  char *ret;
764 
765  /* zlog out if we need to */
766  if (owl_global_is_shutdownlogout(&g)) {
767    owl_zephyr_zlog_out();
768  }
769
770  /* execute the commands in shutdown */
771  ret = owl_perlconfig_execute("owl::shutdown();");
772  if (ret) owl_free(ret);
773
774  /* signal our child process, if any */
775  if (owl_global_get_newmsgproc_pid(&g)) {
776    kill(owl_global_get_newmsgproc_pid(&g), SIGHUP);
777  }
778
779  /* final clean up */
780  owl_zephyr_shutdown();
781  endwin();
782  owl_function_debugmsg("Quitting Owl");
783  exit(0);
784}
785
786
787void owl_function_makemsg(char *fmt, ...)
788{
789  va_list ap;
790  char buff[2048];
791
792  if (!owl_global_get_curs_msgwin(&g)) return;
793
794  va_start(ap, fmt);
795  werase(owl_global_get_curs_msgwin(&g));
796 
797  vsnprintf(buff, 2048, fmt, ap);
798  owl_function_debugmsg("makemsg: %s", buff);
799  waddstr(owl_global_get_curs_msgwin(&g), buff); 
800  wnoutrefresh(owl_global_get_curs_msgwin(&g));
801  owl_global_set_needrefresh(&g);
802  va_end(ap);
803}
804
805void owl_function_errormsg(char *fmt, ...)
806{
807  va_list ap;
808  char buff[2048];
809
810  if (!owl_global_get_curs_msgwin(&g)) return;
811
812  va_start(ap, fmt);
813  werase(owl_global_get_curs_msgwin(&g));
814 
815  vsnprintf(buff, 2048, fmt, ap);
816  owl_function_debugmsg("ERROR: %s", buff);
817  waddstr(owl_global_get_curs_msgwin(&g), buff); 
818  waddstr(owl_global_get_curs_msgwin(&g), "ERROR: "); 
819  wnoutrefresh(owl_global_get_curs_msgwin(&g));
820  owl_global_set_needrefresh(&g);
821  va_end(ap);
822}
823
824
825void owl_function_openurl()
826{
827  /* visit the first url in the current message */
828  owl_message *m;
829  owl_view *v;
830  char *ptr1, *ptr2, *text, url[LINE], tmpbuff[LINE];
831  int webbrowser;
832
833  webbrowser = owl_global_get_webbrowser(&g);
834
835  if (webbrowser < 0 || webbrowser == OWL_WEBBROWSER_NONE) {
836    owl_function_makemsg("No browser selected");
837    return;
838  }
839
840  v=owl_global_get_current_view(&g);
841 
842  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
843
844  if (!m || owl_view_get_size(v)==0) {
845    owl_function_makemsg("No current message selected");
846    return;
847  }
848
849  text=owl_message_get_text(m);
850
851  /* First look for a good URL */ 
852  if ((ptr1=strstr(text, "http://"))!=NULL) {
853    ptr2=strpbrk(ptr1, " \n\t");
854    if (ptr2) {
855      strncpy(url, ptr1, ptr2-ptr1+1);
856      url[ptr2-ptr1+1]='\0';
857    } else {
858      strcpy(url, ptr1);
859    }
860
861    /* if we had <http strip a trailing > */
862    if (ptr1>text && ptr1[-1]=='<') {
863      if (url[strlen(url)-1]=='>') {
864        url[strlen(url)-1]='\0';
865      }
866    }
867  } else if ((ptr1=strstr(text, "https://"))!=NULL) {
868    /* Look for an https URL */ 
869    ptr2=strpbrk(ptr1, " \n\t");
870    if (ptr2) {
871      strncpy(url, ptr1, ptr2-ptr1+1);
872      url[ptr2-ptr1+1]='\0';
873    } else {
874      strcpy(url, ptr1);
875    }
876   
877    /* if we had <http strip a trailing > */
878    if (ptr1>text && ptr1[-1]=='<') {
879      if (url[strlen(url)-1]=='>') {
880        url[strlen(url)-1]='\0';
881      }
882    }
883  } else if ((ptr1=strstr(text, "www."))!=NULL) {
884    /* if we can't find a real url look for www.something */
885    ptr2=strpbrk(ptr1, " \n\t");
886    if (ptr2) {
887      strncpy(url, ptr1, ptr2-ptr1+1);
888      url[ptr2-ptr1+1]='\0';
889    } else {
890      strcpy(url, ptr1);
891    }
892  } else {
893    owl_function_beep();
894    owl_function_makemsg("Could not find URL to open.");
895    return;
896  }
897
898  /* Make sure there aren't any quotes or \'s in the url */
899  for (ptr1 = url; *ptr1; ptr1++) {
900    if (*ptr1 == '"' || *ptr1 == '\\') {
901      owl_function_beep();
902      owl_function_makemsg("URL contains invalid characters.");
903      return;
904    }
905  }
906 
907  /* NOTE: There are potentially serious security issues here... */
908
909  /* open the page */
910  owl_function_makemsg("Opening %s", url);
911  if (webbrowser == OWL_WEBBROWSER_NETSCAPE) {
912    snprintf(tmpbuff, LINE, "netscape -remote \"openURL(%s)\" > /dev/null 2> /dev/null", url);
913    system(tmpbuff); 
914  } else if (webbrowser == OWL_WEBBROWSER_GALEON) {
915    snprintf(tmpbuff, LINE, "galeon \"%s\" > /dev/null 2> /dev/null &", url);
916    system(tmpbuff); 
917  } else if (webbrowser == OWL_WEBBROWSER_OPERA) {
918    snprintf(tmpbuff, LINE, "opera \"%s\" > /dev/null 2> /dev/null &", url);
919    system(tmpbuff); 
920  }
921}
922
923void owl_function_calculate_topmsg(int direction)
924{
925  int recwinlines, topmsg, curmsg;
926  owl_view *v;
927
928  v=owl_global_get_current_view(&g);
929  curmsg=owl_global_get_curmsg(&g);
930  topmsg=owl_global_get_topmsg(&g);
931  recwinlines=owl_global_get_recwin_lines(&g);
932
933  /*
934  if (owl_view_get_size(v) < 1) {
935    return;
936  }
937  */
938
939  switch (owl_global_get_scrollmode(&g)) {
940  case OWL_SCROLLMODE_TOP:
941    topmsg = owl_function_calculate_topmsg_top(direction, v, curmsg, topmsg, recwinlines);
942    break;
943  case OWL_SCROLLMODE_NEARTOP:
944    topmsg = owl_function_calculate_topmsg_neartop(direction, v, curmsg, topmsg, recwinlines);
945    break;
946  case OWL_SCROLLMODE_CENTER:
947    topmsg = owl_function_calculate_topmsg_center(direction, v, curmsg, topmsg, recwinlines);
948    break;
949  case OWL_SCROLLMODE_PAGED:
950    topmsg = owl_function_calculate_topmsg_paged(direction, v, curmsg, topmsg, recwinlines, 0);
951    break;
952  case OWL_SCROLLMODE_PAGEDCENTER:
953    topmsg = owl_function_calculate_topmsg_paged(direction, v, curmsg, topmsg, recwinlines, 1);
954    break;
955  case OWL_SCROLLMODE_NORMAL:
956  default:
957    topmsg = owl_function_calculate_topmsg_normal(direction, v, curmsg, topmsg, recwinlines);
958  }
959  owl_function_debugmsg("Calculated a topmsg of %i", topmsg);
960  owl_global_set_topmsg(&g, topmsg);
961}
962
963/* Returns what the new topmsg should be. 
964 * Passed the last direction of movement,
965 * the current view,
966 * the current message number in the view,
967 * the top message currently being displayed,
968 * and the number of lines in the recwin.
969 */
970int owl_function_calculate_topmsg_top(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines)
971{
972  return(curmsg);
973}
974
975int owl_function_calculate_topmsg_neartop(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines)
976{
977  if (curmsg>0 
978      && (owl_message_get_numlines(owl_view_get_element(v, curmsg-1))
979          <  recwinlines/2)) {
980    return(curmsg-1);
981  } else {
982    return(curmsg);
983  }
984}
985 
986int owl_function_calculate_topmsg_center(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines)
987{
988  int i, last, lines;
989
990  last = curmsg;
991  lines = 0;
992  for (i=curmsg-1; i>=0; i--) {
993    lines += owl_message_get_numlines(owl_view_get_element(v, i));
994    if (lines > recwinlines/2) break;
995    last = i;
996  }
997  return(last);
998}
999 
1000int owl_function_calculate_topmsg_paged(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines, int center_on_page)
1001{
1002  int i, last, lines, savey;
1003 
1004  /* If we're off the top of the screen, scroll up such that the
1005   * curmsg is near the botton of the screen. */
1006  if (curmsg < topmsg) {
1007    last = curmsg;
1008    lines = 0;
1009    for (i=curmsg; i>=0; i--) {
1010      lines += owl_message_get_numlines(owl_view_get_element(v, i));
1011      if (lines > recwinlines) break;
1012    last = i;
1013    }
1014    if (center_on_page) {
1015      return(owl_function_calculate_topmsg_center(direction, v, curmsg, 0, recwinlines));
1016    } else {
1017      return(last);
1018    }
1019  }
1020
1021  /* Find number of lines from top to bottom of curmsg (store in savey) */
1022  savey=0;
1023  for (i=topmsg; i<=curmsg; i++) {
1024    savey+=owl_message_get_numlines(owl_view_get_element(v, i));
1025  }
1026
1027  /* if we're off the bottom of the screen, scroll down */
1028  if (savey > recwinlines) {
1029    if (center_on_page) {
1030      return(owl_function_calculate_topmsg_center(direction, v, curmsg, 0, recwinlines));
1031    } else {
1032      return(curmsg);
1033    }
1034  }
1035
1036  /* else just stay as we are... */
1037  return(topmsg);
1038}
1039
1040
1041int owl_function_calculate_topmsg_normal(int direction, owl_view *v, int curmsg, int topmsg, int recwinlines)
1042{
1043  int savey, j, i, foo, y;
1044
1045  if (curmsg<0) return(topmsg);
1046   
1047  /* If we're off the top of the screen then center */
1048  if (curmsg<topmsg) {
1049    topmsg=owl_function_calculate_topmsg_center(direction, v, curmsg, 0, recwinlines);
1050  }
1051
1052  /* Find number of lines from top to bottom of curmsg (store in savey) */
1053  savey=0;
1054  for (i=topmsg; i<=curmsg; i++) {
1055    savey+=owl_message_get_numlines(owl_view_get_element(v, i));
1056  }
1057
1058  /* If we're off the bottom of the screen, set the topmsg to curmsg
1059   * and scroll upwards */
1060  if (savey > recwinlines) {
1061    topmsg=curmsg;
1062    savey=owl_message_get_numlines(owl_view_get_element(v, i));
1063    direction=OWL_DIRECTION_UPWARDS;
1064  }
1065 
1066  /* If our bottom line is less than 1/4 down the screen then scroll up */
1067  if (direction == OWL_DIRECTION_UPWARDS || direction == OWL_DIRECTION_NONE) {
1068    if (savey < (recwinlines / 4)) {
1069      y=0;
1070      for (j=curmsg; j>=0; j--) {
1071        foo=owl_message_get_numlines(owl_view_get_element(v, j));
1072        /* will we run the curmsg off the screen? */
1073        if ((foo+y) >= recwinlines) {
1074          j++;
1075          if (j>curmsg) j=curmsg;
1076          break;
1077        }
1078        /* have saved 1/2 the screen space? */
1079        y+=foo;
1080        if (y > (recwinlines / 2)) break;
1081      }
1082      if (j<0) j=0;
1083      return(j);
1084    }
1085  }
1086
1087  if (direction == OWL_DIRECTION_DOWNWARDS || direction == OWL_DIRECTION_NONE) {
1088    /* If curmsg bottom line is more than 3/4 down the screen then scroll down */
1089    if (savey > ((recwinlines * 3)/4)) {
1090      y=0;
1091      /* count lines from the top until we can save 1/2 the screen size */
1092      for (j=topmsg; j<curmsg; j++) {
1093        y+=owl_message_get_numlines(owl_view_get_element(v, j));
1094        if (y > (recwinlines / 2)) break;
1095      }
1096      if (j==curmsg) {
1097        j--;
1098      }
1099      return(j+1);
1100    }
1101  }
1102
1103  return(topmsg);
1104}
1105
1106
1107void owl_function_resize()
1108{
1109  owl_global_set_resize_pending(&g);
1110}
1111
1112
1113void owl_function_run_buffercommand()
1114{
1115  char *buff, *ptr;
1116
1117  buff=owl_global_get_buffercommand(&g);
1118  if (!strncmp(buff, "zwrite ", 7)) {
1119    owl_function_zwrite(buff, owl_editwin_get_text(owl_global_get_typwin(&g)));
1120  } else if (!strncmp(buff, "zcrypt ", 7)) {
1121    owl_function_zcrypt(buff, owl_editwin_get_text(owl_global_get_typwin(&g)));
1122  } else if (!strncmp(buff, "aimwrite ", 9)) {
1123    owl_function_aimwrite(buff+9);
1124  } else if (!strncmp(buff, "aimlogin ", 9)) {
1125    ptr=owl_sprintf("%s %s", buff, owl_global_get_response(&g));
1126    owl_function_command(ptr);
1127    owl_free(ptr);
1128  }
1129}
1130
1131void owl_function_debugmsg(char *fmt, ...)
1132{
1133  FILE *file;
1134  time_t now;
1135  char buff1[LINE], buff2[LINE];
1136  va_list ap;
1137  va_start(ap, fmt);
1138
1139  if (!owl_global_is_debug_fast(&g)) return;
1140
1141  file=fopen(owl_global_get_debug_file(&g), "a");
1142  if (!file) return;
1143
1144  now=time(NULL);
1145  strcpy(buff1, ctime(&now));
1146  buff1[strlen(buff1)-1]='\0';
1147
1148  owl_global_get_runtime_string(&g, buff2);
1149 
1150  fprintf(file, "[%i -  %s - %s]: ", (int) getpid(), buff1, buff2);
1151  vfprintf(file, fmt, ap);
1152  fprintf(file, "\n");
1153  fclose(file);
1154
1155  va_end(ap);
1156}
1157
1158
1159void owl_function_refresh()
1160{
1161  owl_function_resize();
1162}
1163
1164void owl_function_beep()
1165{
1166  if (owl_global_is_bell(&g)) {
1167    beep();
1168    owl_global_set_needrefresh(&g); /* do we really need this? */
1169  }
1170}
1171
1172
1173void owl_function_subscribe(char *class, char *inst, char *recip)
1174{
1175  int ret;
1176
1177  ret=owl_zephyr_sub(class, inst, recip);
1178  if (ret) {
1179    owl_function_makemsg("Error subscribing.");
1180  } else {
1181    owl_function_makemsg("Subscribed.");
1182  }
1183}
1184
1185
1186void owl_function_unsubscribe(char *class, char *inst, char *recip)
1187{
1188  int ret;
1189
1190  ret=owl_zephyr_unsub(class, inst, recip);
1191  if (ret) {
1192    owl_function_makemsg("Error subscribing.");
1193  } else {
1194    owl_function_makemsg("Unsubscribed.");
1195  }
1196}
1197
1198
1199void owl_function_set_cursor(WINDOW *win)
1200{
1201  wnoutrefresh(win);
1202}
1203
1204
1205void owl_function_full_redisplay()
1206{
1207  redrawwin(owl_global_get_curs_recwin(&g));
1208  redrawwin(owl_global_get_curs_sepwin(&g));
1209  redrawwin(owl_global_get_curs_typwin(&g));
1210  redrawwin(owl_global_get_curs_msgwin(&g));
1211
1212  wnoutrefresh(owl_global_get_curs_recwin(&g));
1213  wnoutrefresh(owl_global_get_curs_sepwin(&g));
1214  wnoutrefresh(owl_global_get_curs_typwin(&g));
1215  wnoutrefresh(owl_global_get_curs_msgwin(&g));
1216 
1217  sepbar("");
1218  owl_function_makemsg("");
1219
1220  owl_global_set_needrefresh(&g);
1221}
1222
1223
1224void owl_function_popless_text(char *text)
1225{
1226  owl_popwin *pw;
1227  owl_viewwin *v;
1228
1229  pw=owl_global_get_popwin(&g);
1230  v=owl_global_get_viewwin(&g);
1231
1232  owl_popwin_up(pw);
1233  owl_viewwin_init_text(v, owl_popwin_get_curswin(pw),
1234                        owl_popwin_get_lines(pw), owl_popwin_get_cols(pw),
1235                        text);
1236  owl_popwin_refresh(pw);
1237  owl_viewwin_redisplay(v, 0);
1238  owl_global_set_needrefresh(&g);
1239}
1240
1241
1242void owl_function_popless_fmtext(owl_fmtext *fm)
1243{
1244  owl_popwin *pw;
1245  owl_viewwin *v;
1246
1247  pw=owl_global_get_popwin(&g);
1248  v=owl_global_get_viewwin(&g);
1249
1250  owl_popwin_up(pw);
1251  owl_viewwin_init_fmtext(v, owl_popwin_get_curswin(pw),
1252                   owl_popwin_get_lines(pw), owl_popwin_get_cols(pw),
1253                   fm);
1254  owl_popwin_refresh(pw);
1255  owl_viewwin_redisplay(v, 0);
1256  owl_global_set_needrefresh(&g);
1257}
1258
1259void owl_function_about()
1260{
1261  char buff[5000];
1262
1263  sprintf(buff, "This is owl version %s\n", OWL_VERSION_STRING);
1264  strcat(buff, "\nOwl was written by James Kretchmar at the Massachusetts\n");
1265  strcat(buff, "Institute of Technology.  The first version, 0.5, was\n");
1266  strcat(buff, "released in March 2002.\n");
1267  strcat(buff, "\n");
1268  strcat(buff, "The name 'owl' was chosen in reference to the owls in the\n");
1269  strcat(buff, "Harry Potter novels, who are tasked with carrying messages\n");
1270  strcat(buff, "between Witches and Wizards.\n");
1271  strcat(buff, "\n");
1272  strcat(buff, "Copyright 2002 Massachusetts Institute of Technology\n");
1273  strcat(buff, "\n");
1274  strcat(buff, "Permission to use, copy, modify, and distribute this\n");
1275  strcat(buff, "software and its documentation for any purpose and without\n");
1276  strcat(buff, "fee is hereby granted, provided that the above copyright\n");
1277  strcat(buff, "notice and this permission notice appear in all copies\n");
1278  strcat(buff, "and in supporting documentation.  No representation is\n");
1279  strcat(buff, "made about the suitability of this software for any\n");
1280  strcat(buff, "purpose.  It is provided \"as is\" without express\n");
1281  strcat(buff, "or implied warranty.\n");
1282  owl_function_popless_text(buff);
1283}
1284
1285void owl_function_info()
1286{
1287  owl_message *m;
1288  owl_fmtext fm, attrfm;
1289  char buff[10000];
1290  owl_view *v;
1291#ifdef HAVE_LIBZEPHYR
1292  ZNotice_t *n;
1293#endif
1294
1295  owl_fmtext_init_null(&fm);
1296 
1297  v=owl_global_get_current_view(&g);
1298  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
1299  if (!m || owl_view_get_size(v)==0) {
1300    owl_function_makemsg("No message selected\n");
1301    return;
1302  }
1303
1304  owl_fmtext_append_bold(&fm, "General Information:\n");
1305  owl_fmtext_append_normal(&fm, "  Msg Id    : ");
1306  sprintf(buff, "%i", owl_message_get_id(m));
1307  owl_fmtext_append_normal(&fm, buff);
1308  owl_fmtext_append_normal(&fm, "\n");
1309
1310  owl_fmtext_append_normal(&fm, "  Type      : ");
1311  owl_fmtext_append_bold(&fm, owl_message_type_to_string(m));
1312  owl_fmtext_append_normal(&fm, "\n");
1313
1314  if (owl_message_is_direction_in(m)) {
1315    owl_fmtext_append_normal(&fm, "  Direction : in\n");
1316  } else if (owl_message_is_direction_out(m)) {
1317    owl_fmtext_append_normal(&fm, "  Direction : out\n");
1318  } else if (owl_message_is_direction_none(m)) {
1319    owl_fmtext_append_normal(&fm, "  Direction : none\n");
1320  } else {
1321    owl_fmtext_append_normal(&fm, "  Direction : unknown\n");
1322  }
1323
1324  owl_fmtext_append_normal(&fm, "  Time      : ");
1325  owl_fmtext_append_normal(&fm, owl_message_get_timestr(m));
1326  owl_fmtext_append_normal(&fm, "\n");
1327
1328  if (!owl_message_is_type_admin(m)) {
1329    owl_fmtext_append_normal(&fm, "  Sender    : ");
1330    owl_fmtext_append_normal(&fm, owl_message_get_sender(m));
1331    owl_fmtext_append_normal(&fm, "\n");
1332   
1333    owl_fmtext_append_normal(&fm, "  Recipient : ");
1334    owl_fmtext_append_normal(&fm, owl_message_get_recipient(m));
1335    owl_fmtext_append_normal(&fm, "\n");
1336  }
1337   
1338  if (owl_message_is_type_zephyr(m)) {
1339    owl_fmtext_append_bold(&fm, "\nZephyr Specific Information:\n");
1340   
1341    owl_fmtext_append_normal(&fm, "  Class     : ");
1342    owl_fmtext_append_normal(&fm, owl_message_get_class(m));
1343    owl_fmtext_append_normal(&fm, "\n");
1344    owl_fmtext_append_normal(&fm, "  Instance  : ");
1345    owl_fmtext_append_normal(&fm, owl_message_get_instance(m));
1346    owl_fmtext_append_normal(&fm, "\n");
1347    owl_fmtext_append_normal(&fm, "  Opcode    : ");
1348    owl_fmtext_append_normal(&fm, owl_message_get_opcode(m));
1349    owl_fmtext_append_normal(&fm, "\n");
1350   
1351    owl_fmtext_append_normal(&fm, "  Time      : ");
1352    owl_fmtext_append_normal(&fm, owl_message_get_timestr(m));
1353    owl_fmtext_append_normal(&fm, "\n");
1354#ifdef HAVE_LIBZEPHYR
1355    if (owl_message_is_direction_in(m)) {
1356      char *ptr, tmpbuff[1024];
1357      int i, j, fields, len;
1358
1359      n=owl_message_get_notice(m);
1360
1361      owl_fmtext_append_normal(&fm, "  Kind      : ");
1362      if (n->z_kind==UNSAFE) {
1363        owl_fmtext_append_normal(&fm, "UNSAFE\n");
1364      } else if (n->z_kind==UNACKED) {
1365        owl_fmtext_append_normal(&fm, "UNACKED\n");
1366      } else if (n->z_kind==ACKED) {
1367        owl_fmtext_append_normal(&fm, "ACKED\n");
1368      } else if (n->z_kind==HMACK) {
1369        owl_fmtext_append_normal(&fm, "HMACK\n");
1370      } else if (n->z_kind==HMCTL) {
1371        owl_fmtext_append_normal(&fm, "HMCTL\n");
1372      } else if (n->z_kind==SERVACK) {
1373        owl_fmtext_append_normal(&fm, "SERVACK\n");
1374      } else if (n->z_kind==SERVNAK) {
1375        owl_fmtext_append_normal(&fm, "SERVNACK\n");
1376      } else if (n->z_kind==CLIENTACK) {
1377        owl_fmtext_append_normal(&fm, "CLIENTACK\n");
1378      } else if (n->z_kind==STAT) {
1379        owl_fmtext_append_normal(&fm, "STAT\n");
1380      } else {
1381        owl_fmtext_append_normal(&fm, "ILLEGAL VALUE\n");
1382      }
1383      owl_fmtext_append_normal(&fm, "  Host      : ");
1384      owl_fmtext_append_normal(&fm, owl_message_get_hostname(m));
1385      owl_fmtext_append_normal(&fm, "\n");
1386      sprintf(buff, "  Port      : %i\n", n->z_port);
1387      owl_fmtext_append_normal(&fm, buff);
1388
1389      owl_fmtext_append_normal(&fm,    "  Auth      : ");
1390      owl_fmtext_append_normal(&fm, owl_zephyr_get_authstr(n));
1391      owl_fmtext_append_normal(&fm, "\n");
1392
1393      /* fix this */
1394      sprintf(buff, "  Checkd Ath: %i\n", n->z_checked_auth);
1395      sprintf(buff, "%s  Multi notc: %s\n", buff, n->z_multinotice);
1396      sprintf(buff, "%s  Num other : %i\n", buff, n->z_num_other_fields);
1397      sprintf(buff, "%s  Msg Len   : %i\n", buff, n->z_message_len);
1398      owl_fmtext_append_normal(&fm, buff);
1399     
1400      sprintf(buff, "  Fields    : %i\n", owl_zephyr_get_num_fields(n));
1401      owl_fmtext_append_normal(&fm, buff);
1402     
1403      fields=owl_zephyr_get_num_fields(n);
1404      for (i=0; i<fields; i++) {
1405        sprintf(buff, "  Field %i   : ", i+1);
1406       
1407        ptr=owl_zephyr_get_field(n, i+1, &len);
1408        if (!ptr) break;
1409        if (len<30) {
1410          strncpy(tmpbuff, ptr, len);
1411          tmpbuff[len]='\0';
1412        } else {
1413          strncpy(tmpbuff, ptr, 30);
1414          tmpbuff[30]='\0';
1415          strcat(tmpbuff, "...");
1416        }
1417       
1418        for (j=0; j<strlen(tmpbuff); j++) {
1419          if (tmpbuff[j]=='\n') tmpbuff[j]='~';
1420          if (tmpbuff[j]=='\r') tmpbuff[j]='!';
1421        }
1422       
1423        strcat(buff, tmpbuff);
1424        strcat(buff, "\n");
1425        owl_fmtext_append_normal(&fm, buff);
1426      }
1427      owl_fmtext_append_normal(&fm, "  Default Fm:");
1428      owl_fmtext_append_normal(&fm, n->z_default_format);
1429    }
1430#endif   
1431  }
1432
1433  if (owl_message_is_type_aim(m)) {
1434    owl_fmtext_append_bold(&fm, "\nAIM Specific Information:\n");
1435  }
1436
1437  owl_fmtext_append_bold(&fm, "\nOwl Message Attributes:\n");
1438  owl_message_attributes_tofmtext(m, &attrfm);
1439  owl_fmtext_append_fmtext(&fm, &attrfm);
1440 
1441  owl_function_popless_fmtext(&fm);
1442  owl_fmtext_free(&fm);
1443  owl_fmtext_free(&attrfm);
1444}
1445
1446
1447/* print the current message in a popup window.
1448 * Use the 'default' style regardless of whatever
1449 * style the user may be using
1450 */
1451void owl_function_curmsg_to_popwin()
1452{
1453  owl_popwin *pw;
1454  owl_view *v;
1455  owl_message *m;
1456  owl_style *s;
1457  owl_fmtext fm;
1458
1459  v=owl_global_get_current_view(&g);
1460  s=owl_global_get_style_by_name(&g, "default");
1461  pw=owl_global_get_popwin(&g);
1462
1463  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
1464
1465  if (!m || owl_view_get_size(v)==0) {
1466    owl_function_makemsg("No current message");
1467    return;
1468  }
1469
1470  owl_fmtext_init_null(&fm);
1471  owl_style_get_formattext(s, &fm, m);
1472
1473  owl_function_popless_fmtext(&fm);
1474  owl_fmtext_free(&fm);
1475}
1476
1477
1478void owl_function_page_curmsg(int step)
1479{
1480  /* scroll down or up within the current message IF the message is truncated */
1481
1482  int offset, curmsg, lines;
1483  owl_view *v;
1484  owl_message *m;
1485
1486  offset=owl_global_get_curmsg_vert_offset(&g);
1487  v=owl_global_get_current_view(&g);
1488  curmsg=owl_global_get_curmsg(&g);
1489  m=owl_view_get_element(v, curmsg);
1490  if (!m || owl_view_get_size(v)==0) return;
1491  lines=owl_message_get_numlines(m);
1492
1493  if (offset==0) {
1494    /* Bail if the curmsg isn't the last one displayed */
1495    if (curmsg != owl_mainwin_get_last_msg(owl_global_get_mainwin(&g))) {
1496      owl_function_makemsg("The entire message is already displayed");
1497      return;
1498    }
1499   
1500    /* Bail if we're not truncated */
1501    if (!owl_mainwin_is_curmsg_truncated(owl_global_get_mainwin(&g))) {
1502      owl_function_makemsg("The entire message is already displayed");
1503      return;
1504    }
1505  }
1506 
1507 
1508  /* don't scroll past the last line */
1509  if (step>0) {
1510    if (offset+step > lines-1) {
1511      owl_global_set_curmsg_vert_offset(&g, lines-1);
1512    } else {
1513      owl_global_set_curmsg_vert_offset(&g, offset+step);
1514    }
1515  }
1516
1517  /* would we be before the beginning of the message? */
1518  if (step<0) {
1519    if (offset+step<0) {
1520      owl_global_set_curmsg_vert_offset(&g, 0);
1521    } else {
1522      owl_global_set_curmsg_vert_offset(&g, offset+step);
1523    }
1524  }
1525 
1526  /* redisplay */
1527  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1528  owl_global_set_needrefresh(&g);
1529}
1530
1531void owl_function_resize_typwin(int newsize)
1532{
1533  owl_global_set_typwin_lines(&g, newsize);
1534  owl_function_resize();
1535}
1536
1537void owl_function_typwin_grow()
1538{
1539  int i;
1540
1541  i=owl_global_get_typwin_lines(&g);
1542  owl_function_resize_typwin(i+1);
1543}
1544
1545void owl_function_typwin_shrink()
1546{
1547  int i;
1548
1549  i=owl_global_get_typwin_lines(&g);
1550  if (i>2) {
1551    owl_function_resize_typwin(i-1);
1552  }
1553}
1554
1555void owl_function_mainwin_pagedown()
1556{
1557  int i;
1558
1559  i=owl_mainwin_get_last_msg(owl_global_get_mainwin(&g));
1560  if (i<0) return;
1561  if (owl_mainwin_is_last_msg_truncated(owl_global_get_mainwin(&g))
1562      && (owl_global_get_curmsg(&g) < i)
1563      && (i>0)) {
1564    i--;
1565  }
1566  owl_global_set_curmsg(&g, i);
1567  owl_function_nextmsg();
1568}
1569
1570void owl_function_mainwin_pageup()
1571{
1572  owl_global_set_curmsg(&g, owl_global_get_topmsg(&g));
1573  owl_function_prevmsg();
1574}
1575
1576void owl_function_getsubs()
1577{
1578  char *buff;
1579
1580  buff=owl_zephyr_getsubs();
1581
1582  if (buff) {
1583    owl_function_popless_text(buff);
1584  } else {
1585    owl_function_popless_text("Error getting subscriptions");
1586  }
1587           
1588  owl_free(buff);
1589}
1590
1591#define PABUFLEN 5000
1592void owl_function_printallvars()
1593{
1594  char buff[PABUFLEN], *pos, *name;
1595  owl_list varnames;
1596  int i, numvarnames, rem;
1597
1598  pos = buff;
1599  pos += sprintf(pos, "%-20s = %s\n", "VARIABLE", "VALUE");
1600  pos += sprintf(pos, "%-20s   %s\n",  "--------", "-----");
1601  owl_variable_dict_get_names(owl_global_get_vardict(&g), &varnames);
1602  rem = (buff+PABUFLEN)-pos-1;
1603  numvarnames = owl_list_get_size(&varnames);
1604  for (i=0; i<numvarnames; i++) {
1605    name = owl_list_get_element(&varnames, i);
1606    if (name && name[0]!='_') {
1607      rem = (buff+PABUFLEN)-pos-1;   
1608      pos += snprintf(pos, rem, "\n%-20s = ", name);
1609      rem = (buff+PABUFLEN)-pos-1;   
1610      owl_variable_get_tostring(owl_global_get_vardict(&g), name, pos, rem);
1611      pos = buff+strlen(buff);
1612    }
1613  }
1614  rem = (buff+PABUFLEN)-pos-1;   
1615  snprintf(pos, rem, "\n");
1616  owl_variable_dict_namelist_free(&varnames);
1617 
1618  owl_function_popless_text(buff);
1619}
1620
1621void owl_function_show_variables()
1622{
1623  owl_list varnames;
1624  owl_fmtext fm; 
1625  int i, numvarnames;
1626  char *varname;
1627
1628  owl_fmtext_init_null(&fm);
1629  owl_fmtext_append_bold(&fm, 
1630      "Variables: (use 'show variable <name>' for details)\n");
1631  owl_variable_dict_get_names(owl_global_get_vardict(&g), &varnames);
1632  numvarnames = owl_list_get_size(&varnames);
1633  for (i=0; i<numvarnames; i++) {
1634    varname = owl_list_get_element(&varnames, i);
1635    if (varname && varname[0]!='_') {
1636      owl_variable_describe(owl_global_get_vardict(&g), varname, &fm);
1637    }
1638  }
1639  owl_variable_dict_namelist_free(&varnames);
1640  owl_function_popless_fmtext(&fm);
1641  owl_fmtext_free(&fm);
1642}
1643
1644void owl_function_show_variable(char *name)
1645{
1646  owl_fmtext fm; 
1647
1648  owl_fmtext_init_null(&fm);
1649  owl_variable_get_help(owl_global_get_vardict(&g), name, &fm);
1650  owl_function_popless_fmtext(&fm);
1651  owl_fmtext_free(&fm); 
1652}
1653
1654/* note: this applies to global message list, not to view.
1655 * If flag is 1, deletes.  If flag is 0, undeletes. */
1656void owl_function_delete_by_id(int id, int flag)
1657{
1658  owl_messagelist *ml;
1659  owl_message *m;
1660  ml = owl_global_get_msglist(&g);
1661  m = owl_messagelist_get_by_id(ml, id);
1662  if (m) {
1663    if (flag == 1) {
1664      owl_message_mark_delete(m);
1665    } else if (flag == 0) {
1666      owl_message_unmark_delete(m);
1667    }
1668    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1669    owl_global_set_needrefresh(&g);
1670  } else {
1671    owl_function_makemsg("No message with id %d: unable to mark for (un)delete",id);
1672  }
1673}
1674
1675void owl_function_delete_automsgs()
1676{
1677  /* mark for deletion all messages in the current view that match the
1678   * 'trash' filter */
1679
1680  int i, j, count;
1681  owl_message *m;
1682  owl_view *v;
1683  owl_filter *f;
1684
1685  /* get the trash filter */
1686  f=owl_global_get_filter(&g, "trash");
1687  if (!f) {
1688    owl_function_makemsg("No trash filter defined");
1689    return;
1690  }
1691
1692  v=owl_global_get_current_view(&g);
1693
1694  count=0;
1695  j=owl_view_get_size(v);
1696  for (i=0; i<j; i++) {
1697    m=owl_view_get_element(v, i);
1698    if (owl_filter_message_match(f, m)) {
1699      count++;
1700      owl_message_mark_delete(m);
1701    }
1702  }
1703  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1704  owl_function_makemsg("%i messages marked for deletion", count);
1705  owl_global_set_needrefresh(&g);
1706}
1707
1708
1709void owl_function_status()
1710{
1711  char buff[5000];
1712  time_t start;
1713  int up, days, hours, minutes;
1714  owl_fmtext fm;
1715
1716  owl_fmtext_init_null(&fm);
1717
1718  start=owl_global_get_starttime(&g);
1719
1720  owl_fmtext_append_normal(&fm, "Version: ");
1721  owl_fmtext_append_normal(&fm, OWL_VERSION_STRING);
1722  owl_fmtext_append_normal(&fm, "\n");
1723
1724  sprintf(buff, "Screen size: %i lines, %i columns\n", owl_global_get_lines(&g), owl_global_get_cols(&g));
1725  owl_fmtext_append_normal(&fm, buff);
1726
1727  owl_fmtext_append_normal(&fm, "Startup Arugments: ");
1728  owl_fmtext_append_normal(&fm, owl_global_get_startupargs(&g));
1729  owl_fmtext_append_normal(&fm, "\n");
1730  sprintf(buff, "Startup Time: %s", ctime(&start));
1731  owl_fmtext_append_normal(&fm, buff);
1732 
1733
1734  up=owl_global_get_runtime(&g);
1735  days=up/86400;
1736  up-=days*86400;
1737  hours=up/3600;
1738  up-=hours*3600;
1739  minutes=up/60;
1740  up-=minutes*60;
1741  sprintf(buff, "Run Time: %i days %2.2i:%2.2i:%2.2i\n", days, hours, minutes, up);
1742  owl_fmtext_append_normal(&fm, buff);
1743
1744  if (owl_global_get_hascolors(&g)) {
1745    sprintf(buff, "Color: Yes, %i color pairs.\n", owl_global_get_colorpairs(&g));
1746  } else {
1747    sprintf(buff, "Color: No.\n");
1748  }
1749  owl_fmtext_append_normal(&fm, buff);
1750
1751  /*
1752  sprintf(buff, "%sMemory Malloced: %i\n", buff, owl_global_get_malloced(&g));
1753  sprintf(buff, "%sMemory Freed: %i\n", buff, owl_global_get_freed(&g));
1754  sprintf(buff, "%sMemory In Use: %i\n", buff, owl_global_get_meminuse(&g));
1755  */
1756
1757  owl_fmtext_append_normal(&fm, "\n");
1758  if (owl_global_is_aimloggedin(&g)) {
1759    owl_fmtext_append_normal(&fm, "AIM: logged in as ");
1760    owl_fmtext_append_normal(&fm, owl_global_get_aim_screenname(&g));
1761    owl_fmtext_append_normal(&fm, "\n");
1762  } else {
1763    owl_fmtext_append_normal(&fm, "AIM: not logged in\n");
1764  }
1765  if (owl_global_is_doaimevents(&g)) {
1766    owl_fmtext_append_normal(&fm, "AIM: processing events\n ");
1767  } else {
1768    owl_fmtext_append_normal(&fm, "AIM: not processing events\n ");
1769  }
1770
1771  owl_function_popless_fmtext(&fm);
1772  owl_fmtext_free(&fm);
1773}
1774
1775void owl_function_show_term()
1776{
1777  owl_fmtext fm;
1778  char buff[LINE];
1779
1780  owl_fmtext_init_null(&fm);
1781  sprintf(buff, "Terminal Lines: %i\nTerminal Columns: %i\n",
1782          owl_global_get_lines(&g),
1783          owl_global_get_cols(&g));
1784  owl_fmtext_append_normal(&fm, buff);
1785
1786  if (owl_global_get_hascolors(&g)) {
1787    owl_fmtext_append_normal(&fm, "Color: Yes\n");
1788    sprintf(buff, "Number of color pairs: %i\n", owl_global_get_colorpairs(&g));
1789    owl_fmtext_append_normal(&fm, buff);
1790    sprintf(buff, "Can change colors: %s\n", can_change_color() ? "yes" : "no");
1791    owl_fmtext_append_normal(&fm, buff);
1792  } else {
1793    owl_fmtext_append_normal(&fm, "Color: No\n");
1794  }
1795
1796  owl_function_popless_fmtext(&fm);
1797  owl_fmtext_free(&fm);
1798}
1799
1800
1801/* if type = 0 then normal reply.
1802 * if type = 1 then it's a reply to sender
1803 * if enter = 0 then allow the command to be edited
1804 * if enter = 1 then don't wait for editing
1805 */
1806void owl_function_reply(int type, int enter)
1807{
1808  char *buff=NULL, *oldbuff;
1809  owl_message *m;
1810  owl_filter *f;
1811 
1812  if (owl_view_get_size(owl_global_get_current_view(&g))==0) {
1813    owl_function_makemsg("No message selected");
1814  } else {
1815    char *class, *inst, *to, *cc=NULL;
1816   
1817    m=owl_view_get_element(owl_global_get_current_view(&g), owl_global_get_curmsg(&g));
1818    if (!m) {
1819      owl_function_makemsg("No message selected");
1820      return;
1821    }
1822
1823    /* first check if we catch the reply-lockout filter */
1824    f=owl_global_get_filter(&g, "reply-lockout");
1825    if (f) {
1826      if (owl_filter_message_match(f, m)) {
1827        owl_function_makemsg("Sorry, replies to this message have been disabled by the reply-lockout filter");
1828        return;
1829      }
1830    }
1831
1832    /* admin */
1833    if (owl_message_is_type_admin(m)) {
1834      owl_function_makemsg("You cannot reply to an admin message");
1835      return;
1836    }
1837
1838    /* zephyr */
1839    if (owl_message_is_type_zephyr(m)) {
1840      /* if it's a zephyr we sent, send it out the same way again */
1841      if (owl_message_is_direction_out(m)) {
1842        owl_function_zwrite_setup(owl_message_get_zwriteline(m));
1843        owl_global_set_buffercommand(&g, owl_message_get_zwriteline(m));
1844        return;
1845      }
1846
1847      /* Special case a personal reply to a webzephyr user on a class */
1848      if ((type==1) && !strcasecmp(owl_message_get_opcode(m), OWL_WEBZEPHYR_OPCODE)) {
1849        class=OWL_WEBZEPHYR_CLASS;
1850        inst=owl_message_get_sender(m);
1851        to=OWL_WEBZEPHYR_PRINCIPAL;
1852      } else if (!strcasecmp(owl_message_get_class(m), OWL_WEBZEPHYR_CLASS) && owl_message_is_loginout(m)) {
1853        /* Special case LOGIN/LOGOUT notifications on class "webzephyr" */
1854        class=OWL_WEBZEPHYR_CLASS;
1855        inst=owl_message_get_instance(m);
1856        to=OWL_WEBZEPHYR_PRINCIPAL;
1857      } else if (owl_message_is_loginout(m)) {
1858        /* Normal LOGIN/LOGOUT messages */
1859        class="MESSAGE";
1860        inst="PERSONAL";
1861        to=owl_message_get_sender(m);
1862      } else if (type==1) {
1863        /* Personal reply */
1864        class="MESSAGE";
1865        inst="PERSONAL";
1866        to=owl_message_get_sender(m);
1867      } else {
1868        /* General reply */
1869        class=owl_message_get_class(m);
1870        inst=owl_message_get_instance(m);
1871        to=owl_message_get_recipient(m);
1872        cc=owl_message_get_cc(m);
1873        if (!strcmp(to, "") || !strcmp(to, "*")) {
1874          to="";
1875        } else if (to[0]=='@') {
1876          /* leave it, to get the realm */
1877        } else {
1878          to=owl_message_get_sender(m);
1879        }
1880      }
1881       
1882      /* create the command line */
1883      if (!strcasecmp(owl_message_get_opcode(m), "CRYPT")) {
1884        buff=owl_strdup("zcrypt");
1885      } else {
1886        buff = owl_strdup("zwrite");
1887      }
1888      if (strcasecmp(class, "message")) {
1889        buff = owl_sprintf("%s -c %s%s%s", oldbuff=buff, owl_getquoting(class), class, owl_getquoting(class));
1890        owl_free(oldbuff);
1891      }
1892      if (strcasecmp(inst, "personal")) {
1893        buff = owl_sprintf("%s -i %s%s%s", oldbuff=buff, owl_getquoting(inst), inst, owl_getquoting(inst));
1894        owl_free(oldbuff);
1895      }
1896      if (*to != '\0') {
1897        char *tmp, *oldtmp, *tmp2;
1898        tmp=short_zuser(to);
1899        if (cc) {
1900          tmp = owl_util_uniq(oldtmp=tmp, cc, "-");
1901          owl_free(oldtmp);
1902          buff = owl_sprintf("%s -C %s", oldbuff=buff, tmp);
1903          owl_free(oldbuff);
1904        } else {
1905          if (owl_global_is_smartstrip(&g)) {
1906            tmp2=tmp;
1907            tmp=owl_util_smartstripped_user(tmp2);
1908            owl_free(tmp2);
1909          }
1910          buff = owl_sprintf("%s %s", oldbuff=buff, tmp);
1911          owl_free(oldbuff);
1912        }
1913        owl_free(tmp);
1914      }
1915      if (cc) owl_free(cc);
1916    }
1917
1918    /* aim */
1919    if (owl_message_is_type_aim(m)) {
1920      if (owl_message_is_direction_out(m)) {
1921        buff=owl_sprintf("aimwrite %s", owl_message_get_recipient(m));
1922      } else {
1923        buff=owl_sprintf("aimwrite %s", owl_message_get_sender(m));
1924      }
1925    }
1926   
1927    if (enter) {
1928      owl_history *hist = owl_global_get_cmd_history(&g);
1929      owl_history_store(hist, buff);
1930      owl_history_reset(hist);
1931      owl_function_command_norv(buff);
1932    } else {
1933      owl_function_start_command(buff);
1934    }
1935    owl_free(buff);
1936  }
1937}
1938
1939void owl_function_zlocate(int argc, char **argv, int auth)
1940{
1941  owl_fmtext fm;
1942  char *ptr, buff[LINE];
1943  int i;
1944
1945  owl_fmtext_init_null(&fm);
1946
1947  for (i=0; i<argc; i++) {
1948    ptr=long_zuser(argv[i]);
1949    owl_zephyr_zlocate(ptr, buff, auth);
1950    owl_fmtext_append_normal(&fm, buff);
1951    owl_free(ptr);
1952  }
1953
1954  owl_function_popless_fmtext(&fm);
1955  owl_fmtext_free(&fm);
1956}
1957
1958void owl_function_start_command(char *line)
1959{
1960  int i, j;
1961  owl_editwin *tw;
1962
1963  tw=owl_global_get_typwin(&g);
1964  owl_global_set_typwin_active(&g);
1965  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, 
1966                        owl_global_get_cmd_history(&g));
1967
1968  owl_editwin_set_locktext(tw, "command: ");
1969  owl_global_set_needrefresh(&g);
1970
1971  j=strlen(line);
1972  for (i=0; i<j; i++) {
1973    owl_editwin_process_char(tw, line[i]);
1974  }
1975  owl_editwin_redisplay(tw, 0);
1976
1977  owl_context_set_editline(owl_global_get_context(&g), tw);
1978  owl_function_activate_keymap("editline");
1979   
1980}
1981
1982void owl_function_start_question(char *line)
1983{
1984  owl_editwin *tw;
1985
1986  tw=owl_global_get_typwin(&g);
1987  owl_global_set_typwin_active(&g);
1988  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, owl_global_get_cmd_history(&g));
1989
1990  owl_editwin_set_locktext(tw, line);
1991  owl_global_set_needrefresh(&g);
1992
1993  owl_editwin_redisplay(tw, 0);
1994
1995  owl_context_set_editresponse(owl_global_get_context(&g), tw);
1996  owl_function_activate_keymap("editresponse");
1997}
1998
1999void owl_function_start_password(char *line)
2000{
2001  owl_editwin *tw;
2002
2003  tw=owl_global_get_typwin(&g);
2004  owl_global_set_typwin_active(&g);
2005  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, owl_global_get_cmd_history(&g));
2006  owl_editwin_set_echochar(tw, '*');
2007
2008  owl_editwin_set_locktext(tw, line);
2009  owl_global_set_needrefresh(&g);
2010
2011  owl_editwin_redisplay(tw, 0);
2012
2013  owl_context_set_editresponse(owl_global_get_context(&g), tw);
2014  owl_function_activate_keymap("editresponse");
2015}
2016
2017char *owl_function_exec(int argc, char **argv, char *buff, int type)
2018{
2019  /* if type == 1 display in a popup
2020   * if type == 2 display an admin messages
2021   * if type == 0 return output
2022   * else display in a popup
2023   */
2024  char *newbuff, *redirect = " 2>&1 < /dev/null";
2025  char *out, buff2[1024];
2026  int size;
2027  FILE *p;
2028
2029  if (argc<2) {
2030    owl_function_makemsg("Wrong number of arguments to the exec command");
2031    return NULL;
2032  }
2033
2034  buff = skiptokens(buff, 1);
2035  newbuff = owl_malloc(strlen(buff)+strlen(redirect)+1);
2036  strcpy(newbuff, buff);
2037  strcat(newbuff, redirect);
2038
2039  p=popen(newbuff, "r");
2040  out=owl_malloc(1024);
2041  size=1024;
2042  strcpy(out, "");
2043  while (fgets(buff2, 1024, p)!=NULL) {
2044    size+=1024;
2045    out=owl_realloc(out, size);
2046    strcat(out, buff2);
2047  }
2048  pclose(p);
2049
2050  if (type==1) {
2051    owl_function_popless_text(out);
2052  } else if (type==0) {
2053    return out;
2054  } else if (type==2) {
2055    owl_function_adminmsg(buff, out);
2056  } else {
2057    owl_function_popless_text(out);
2058  }
2059  owl_free(out);
2060  return NULL;
2061}
2062
2063
2064char *owl_function_perl(int argc, char **argv, char *buff, int type)
2065{
2066  /* if type == 1 display in a popup
2067   * if type == 2 display an admin messages
2068   * if type == 0 return output
2069   * else display in a popup
2070   */
2071  char *perlout;
2072
2073  if (argc<2) {
2074    owl_function_makemsg("Wrong number of arguments to perl command");
2075    return NULL;
2076  }
2077
2078  /* consume first token (argv[0]) */
2079  buff = skiptokens(buff, 1);
2080
2081  perlout = owl_perlconfig_execute(buff);
2082  if (perlout) { 
2083    if (type==1) {
2084      owl_function_popless_text(perlout);
2085    } else if (type==2) {
2086      owl_function_adminmsg(buff, perlout);
2087    } else if (type==0) {
2088      return perlout;
2089    } else {
2090      owl_function_popless_text(perlout);
2091    }
2092    owl_free(perlout);
2093  }
2094  return NULL;
2095}
2096
2097#if 0
2098void owl_function_change_view_old(char *filtname)
2099{
2100  owl_view *v;
2101  owl_filter *f;
2102  int curid=-1, newpos, curmsg;
2103  owl_message *curm=NULL;
2104
2105  v=owl_global_get_current_view(&g);
2106  curmsg=owl_global_get_curmsg(&g);
2107  if (curmsg==-1) {
2108    owl_function_debugmsg("Hit the curmsg==-1 case in change_view");
2109  } else {
2110    curm=owl_view_get_element(v, curmsg);
2111    if (curm) {
2112      curid=owl_message_get_id(curm);
2113      owl_view_save_curmsgid(v, curid);
2114    }
2115  }
2116
2117  /* grab the filter */;
2118  f=owl_global_get_filter(&g, filtname);
2119  if (!f) {
2120    owl_function_makemsg("Unknown filter");
2121    return;
2122  }
2123
2124  /* free the existing view and create a new one based on the filter */
2125  owl_view_free(v);
2126  owl_view_create(v, f);
2127
2128  /* Figure out what to set the current message to.
2129   * - If the view we're leaving has messages in it, go to the closest message
2130   *   to the last message pointed to in that view.
2131   * - If the view we're leaving is empty, try to restore the position
2132   *   from the last time we were in the new view.  */
2133  if (curm) {
2134    newpos = owl_view_get_nearest_to_msgid(v, curid);
2135  } else {
2136    newpos = owl_view_get_nearest_to_saved(v);
2137  }
2138
2139  owl_global_set_curmsg(&g, newpos);
2140
2141  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
2142  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2143  owl_global_set_direction_downwards(&g);
2144}
2145#endif
2146
2147void owl_function_change_view(char *filtname)
2148{
2149  owl_view *v;
2150  owl_filter *f;
2151  int curid=-1, newpos, curmsg;
2152  owl_message *curm=NULL;
2153
2154  v=owl_global_get_current_view(&g);
2155
2156  curmsg=owl_global_get_curmsg(&g);
2157  if (curmsg==-1) {
2158    owl_function_debugmsg("Hit the curmsg==-1 case in change_view");
2159  } else {
2160    curm=owl_view_get_element(v, curmsg);
2161    if (curm) {
2162      curid=owl_message_get_id(curm);
2163      owl_view_save_curmsgid(v, curid);
2164    }
2165  }
2166
2167  f=owl_global_get_filter(&g, filtname);
2168  if (!f) {
2169    owl_function_makemsg("Unknown filter");
2170    return;
2171  }
2172
2173  owl_view_new_filter(v, f);
2174
2175  /* Figure out what to set the current message to.
2176   * - If the view we're leaving has messages in it, go to the closest message
2177   *   to the last message pointed to in that view.
2178   * - If the view we're leaving is empty, try to restore the position
2179   *   from the last time we were in the new view.  */
2180  if (curm) {
2181    newpos = owl_view_get_nearest_to_msgid(v, curid);
2182  } else {
2183    newpos = owl_view_get_nearest_to_saved(v);
2184  }
2185
2186  owl_global_set_curmsg(&g, newpos);
2187  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
2188  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2189  owl_global_set_direction_downwards(&g);
2190}
2191
2192void owl_function_create_filter(int argc, char **argv)
2193{
2194  owl_filter *f;
2195  owl_view *v;
2196  int ret, inuse=0;
2197
2198  if (argc < 2) {
2199    owl_function_makemsg("Wrong number of arguments to filter command");
2200    return;
2201  }
2202
2203  v=owl_global_get_current_view(&g);
2204
2205  /* don't touch the all filter */
2206  if (!strcmp(argv[1], "all")) {
2207    owl_function_makemsg("You may not change the 'all' filter.");
2208    return;
2209  }
2210
2211  /* deal with the case of trying change the filter color */
2212  if (argc==4 && !strcmp(argv[2], "-c")) {
2213    f=owl_global_get_filter(&g, argv[1]);
2214    if (!f) {
2215      owl_function_makemsg("The filter '%s' does not exist.", argv[1]);
2216      return;
2217    }
2218    owl_filter_set_color(f, owl_util_string_to_color(argv[3]));
2219    owl_global_set_needrefresh(&g);
2220    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2221    return;
2222  }
2223
2224  /* create the filter and check for errors */
2225  f=owl_malloc(sizeof(owl_filter));
2226  ret=owl_filter_init(f, argv[1], argc-2, argv+2);
2227  if (ret==-1) {
2228    owl_free(f);
2229    owl_function_makemsg("Invalid filter syntax");
2230    return;
2231  }
2232
2233  /* if the named filter is in use by the current view, remember it */
2234  if (!strcmp(owl_view_get_filtname(v), argv[1])) {
2235    inuse=1;
2236  }
2237
2238  /* if the named filter already exists, nuke it */
2239  if (owl_global_get_filter(&g, argv[1])) {
2240    owl_global_remove_filter(&g, argv[1]);
2241  }
2242
2243  /* add the filter */
2244  owl_global_add_filter(&g, f);
2245
2246  /* if it was in use by the current view then update */
2247  if (inuse) {
2248    owl_function_change_view(argv[1]);
2249  }
2250  owl_global_set_needrefresh(&g);
2251  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2252}
2253
2254void owl_function_show_filters()
2255{
2256  owl_list *l;
2257  owl_filter *f;
2258  int i, j;
2259  owl_fmtext fm;
2260
2261  owl_fmtext_init_null(&fm);
2262
2263  l=owl_global_get_filterlist(&g);
2264  j=owl_list_get_size(l);
2265
2266  owl_fmtext_append_bold(&fm, "Filters:\n");
2267
2268  for (i=0; i<j; i++) {
2269    f=owl_list_get_element(l, i);
2270    owl_fmtext_append_normal(&fm, "   ");
2271    if (owl_global_get_hascolors(&g)) {
2272      owl_fmtext_append_normal_color(&fm, owl_filter_get_name(f), owl_filter_get_color(f));
2273    } else {
2274      owl_fmtext_append_normal(&fm, owl_filter_get_name(f));
2275    }
2276    owl_fmtext_append_normal(&fm, "\n");
2277  }
2278  owl_function_popless_fmtext(&fm);
2279  owl_fmtext_free(&fm);
2280}
2281
2282void owl_function_show_filter(char *name)
2283{
2284  owl_filter *f;
2285  char buff[5000];
2286
2287  f=owl_global_get_filter(&g, name);
2288  if (!f) {
2289    owl_function_makemsg("There is no filter with that name");
2290    return;
2291  }
2292  owl_filter_print(f, buff);
2293  owl_function_popless_text(buff);
2294}
2295
2296void owl_function_show_zpunts()
2297{
2298  owl_filter *f;
2299  owl_list *fl;
2300  char buff[5000];
2301  owl_fmtext fm;
2302  int i, j;
2303
2304  owl_fmtext_init_null(&fm);
2305
2306  fl=owl_global_get_puntlist(&g);
2307  j=owl_list_get_size(fl);
2308  owl_fmtext_append_bold(&fm, "Active zpunt filters:\n");
2309
2310  for (i=0; i<j; i++) {
2311    f=owl_list_get_element(fl, i);
2312    owl_filter_print(f, buff);
2313    owl_fmtext_append_normal(&fm, buff);
2314  }
2315  owl_function_popless_fmtext(&fm);
2316  owl_fmtext_free(&fm);
2317}
2318
2319/* Create a filter for a class, instance if one doesn't exist.  If
2320 * instance is NULL then catch all messgaes in the class.  Returns the
2321 * name of the filter, which the caller must free.
2322 */
2323char *owl_function_classinstfilt(char *class, char *instance) 
2324{
2325  owl_list *fl;
2326  owl_filter *f;
2327  char *argbuff, *filtname;
2328  char *tmpclass, *tmpinstance = NULL;
2329  int len;
2330
2331  fl=owl_global_get_filterlist(&g);
2332
2333  /* name for the filter */
2334  len=strlen(class)+30;
2335  if (instance) len+=strlen(instance);
2336  filtname=owl_malloc(len);
2337  if (!instance) {
2338    sprintf(filtname, "class-%s", class);
2339  } else {
2340    sprintf(filtname, "class-%s-instance-%s", class, instance);
2341  }
2342  /* downcase it */
2343  downstr(filtname);
2344  /* turn spaces into hyphens */
2345  owl_util_tr(filtname, ' ', '.');
2346 
2347  /* if it already exists then go with it.  This lets users override */
2348  if (owl_global_get_filter(&g, filtname)) {
2349    return(filtname);
2350  }
2351
2352  /* create the new filter */
2353  argbuff=owl_malloc(len+20);
2354  tmpclass=owl_strdup(class);
2355  owl_util_tr(tmpclass, ' ', '.');
2356  if (instance) {
2357    tmpinstance=owl_strdup(instance);
2358    owl_util_tr(tmpinstance, ' ', '.');
2359  }
2360  sprintf(argbuff, "( class ^%s$ )", tmpclass);
2361  if (tmpinstance) {
2362    sprintf(argbuff, "%s and ( instance ^%s$ )", argbuff, tmpinstance);
2363  }
2364  owl_free(tmpclass);
2365  if (tmpinstance) owl_free(tmpinstance);
2366
2367  f=owl_malloc(sizeof(owl_filter));
2368  owl_filter_init_fromstring(f, filtname, argbuff);
2369
2370  /* add it to the global list */
2371  owl_global_add_filter(&g, f);
2372
2373  owl_free(argbuff);
2374  return(filtname);
2375}
2376
2377/* Create a filter for personal zephyrs to or from the specified
2378 * zephyr user.  Includes login/logout notifications for the user.
2379 * The name of the filter will be 'user-<user>'.  If a filter already
2380 * exists with this name, no new filter will be created.  This allows
2381 * the configuration to override this function.  Returns the name of
2382 * the filter, which the caller must free.
2383 */
2384char *owl_function_zuserfilt(char *user)
2385{
2386  owl_filter *f;
2387  char *argbuff, *longuser, *shortuser, *filtname;
2388
2389  /* stick the local realm on if it's not there */
2390  longuser=long_zuser(user);
2391  shortuser=short_zuser(user);
2392
2393  /* name for the filter */
2394  filtname=owl_malloc(strlen(shortuser)+20);
2395  sprintf(filtname, "user-%s", shortuser);
2396
2397  /* if it already exists then go with it.  This lets users override */
2398  if (owl_global_get_filter(&g, filtname)) {
2399    return(owl_strdup(filtname));
2400  }
2401
2402  /* create the new-internal filter */
2403  f=owl_malloc(sizeof(owl_filter));
2404
2405  argbuff=owl_malloc(strlen(longuser)+1000);
2406  sprintf(argbuff, "( type ^zephyr$ and ( class ^message$ and instance ^personal$ and ");
2407  sprintf(argbuff, "%s ( ( direction ^in$ and sender ^%s$ ) or ( direction ^out$ and recipient ^%s$ ) ) )", argbuff, longuser, longuser);
2408  sprintf(argbuff, "%s or ( ( class ^login$ ) and ( sender ^%s$ ) ) )", argbuff, longuser);
2409
2410  owl_filter_init_fromstring(f, filtname, argbuff);
2411
2412  /* add it to the global list */
2413  owl_global_add_filter(&g, f);
2414
2415  /* free stuff */
2416  owl_free(argbuff);
2417  owl_free(longuser);
2418  owl_free(shortuser);
2419
2420  return(filtname);
2421}
2422
2423/* Create a filter for AIM IM messages to or from the specified
2424 * screenname.  The name of the filter will be 'aimuser-<user>'.  If a
2425 * filter already exists with this name, no new filter will be
2426 * created.  This allows the configuration to override this function.
2427 * Returns the name of the filter, which the caller must free.
2428 */
2429char *owl_function_aimuserfilt(char *user)
2430{
2431  owl_filter *f;
2432  char *argbuff, *filtname;
2433
2434  /* name for the filter */
2435  filtname=owl_malloc(strlen(user)+40);
2436  sprintf(filtname, "aimuser-%s", user);
2437
2438  /* if it already exists then go with it.  This lets users override */
2439  if (owl_global_get_filter(&g, filtname)) {
2440    return(owl_strdup(filtname));
2441  }
2442
2443  /* create the new-internal filter */
2444  f=owl_malloc(sizeof(owl_filter));
2445
2446  argbuff=owl_malloc(1000);
2447  sprintf(argbuff,
2448          "( type ^aim$ and ( ( sender ^%s$ and recipient ^%s$ ) or ( sender ^%s$ and recipient ^%s$ ) ) )",
2449          user, owl_global_get_aim_screenname(&g), owl_global_get_aim_screenname(&g), user);
2450
2451  owl_filter_init_fromstring(f, filtname, argbuff);
2452
2453  /* add it to the global list */
2454  owl_global_add_filter(&g, f);
2455
2456  /* free stuff */
2457  owl_free(argbuff);
2458
2459  return(filtname);
2460}
2461
2462char *owl_function_typefilt(char *type)
2463{
2464  owl_filter *f;
2465  char *argbuff, *filtname;
2466
2467  /* name for the filter */
2468  filtname=owl_sprintf("type-%s", type);
2469
2470  /* if it already exists then go with it.  This lets users override */
2471  if (owl_global_get_filter(&g, filtname)) {
2472    return filtname;
2473  }
2474
2475  /* create the new-internal filter */
2476  f=owl_malloc(sizeof(owl_filter));
2477
2478  argbuff = owl_sprintf("type ^%s$", type);
2479
2480  owl_filter_init_fromstring(f, filtname, argbuff);
2481
2482  /* add it to the global list */
2483  owl_global_add_filter(&g, f);
2484
2485  /* free stuff */
2486  owl_free(argbuff);
2487
2488  return filtname;
2489}
2490
2491/* If flag is 1, marks for deletion.  If flag is 0,
2492 * unmarks for deletion. */
2493void owl_function_delete_curview_msgs(int flag)
2494{
2495  owl_view *v;
2496  int i, j;
2497
2498  v=owl_global_get_current_view(&g);
2499  j=owl_view_get_size(v);
2500  for (i=0; i<j; i++) {
2501    if (flag == 1) {
2502      owl_message_mark_delete(owl_view_get_element(v, i));
2503    } else if (flag == 0) {
2504      owl_message_unmark_delete(owl_view_get_element(v, i));
2505    }
2506  }
2507
2508  owl_function_makemsg("%i messages marked for %sdeletion", j, flag?"":"un");
2509
2510  owl_mainwin_redisplay(owl_global_get_mainwin(&g)); 
2511}
2512
2513/* Create a filter based on the current message.  Returns the name of
2514 * a filter or null.  The caller must free this name.
2515 *
2516 * if the curmsg is a personal zephyr return a filter name
2517 *    to the zephyr converstaion with that user.
2518 * If the curmsg is a zephyr class message, instance foo, recip *,
2519 *    return a filter name to the class, inst.
2520 * If the curmsg is a zephyr class message and type==0 then
2521 *    return a filter name for just the class.
2522 * If the curmsg is a zephyr class message and type==1 then
2523 *    return a filter name for the class and instance.
2524 * If the curmsg is a personal AIM message returna  filter
2525 *    name to the AIM conversation with that user
2526 */
2527char *owl_function_smartfilter(int type)
2528{
2529  owl_view *v;
2530  owl_message *m;
2531  char *zperson, *filtname=NULL;
2532 
2533  v=owl_global_get_current_view(&g);
2534  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2535
2536  if (!m || owl_view_get_size(v)==0) {
2537    owl_function_makemsg("No message selected\n");
2538    return(NULL);
2539  }
2540
2541  /* very simple handling of admin messages for now */
2542  if (owl_message_is_type_admin(m)) {
2543    return(owl_function_typefilt("admin"));
2544  }
2545
2546  /* aim messages */
2547  if (owl_message_is_type_aim(m)) {
2548    if (owl_message_is_direction_in(m)) {
2549      filtname=owl_function_aimuserfilt(owl_message_get_sender(m));
2550    } else if (owl_message_is_direction_out(m)) {
2551      filtname=owl_function_aimuserfilt(owl_message_get_recipient(m));
2552    }
2553    return(filtname);
2554  }
2555
2556  /* narrow personal and login messages to the sender or recip as appropriate */
2557  if (owl_message_is_personal(m) || owl_message_is_loginout(m)) {
2558    if (owl_message_is_type_zephyr(m)) {
2559      if (owl_message_is_direction_in(m)) {
2560        zperson=short_zuser(owl_message_get_sender(m));
2561      } else {
2562        zperson=short_zuser(owl_message_get_recipient(m));
2563      }
2564      filtname=owl_function_zuserfilt(zperson);
2565      owl_free(zperson);
2566      return(filtname);
2567    }
2568    return(NULL);
2569  }
2570
2571  /* narrow class MESSAGE, instance foo, recip * messages to class, inst */
2572  if (!strcasecmp(owl_message_get_class(m), "message") && !owl_message_is_personal(m)) {
2573    filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2574    return(filtname);
2575  }
2576
2577  /* otherwise narrow to the class */
2578  if (type==0) {
2579    filtname=owl_function_classinstfilt(owl_message_get_class(m), NULL);
2580  } else if (type==1) {
2581    filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2582  }
2583  return(filtname);
2584}
2585
2586void owl_function_smartzpunt(int type)
2587{
2588  /* Starts a zpunt command based on the current class,instance pair.
2589   * If type=0, uses just class.  If type=1, uses instance as well. */
2590  owl_view *v;
2591  owl_message *m;
2592  char *cmd, *cmdprefix, *mclass, *minst;
2593 
2594  v=owl_global_get_current_view(&g);
2595  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2596
2597  if (!m || owl_view_get_size(v)==0) {
2598    owl_function_makemsg("No message selected\n");
2599    return;
2600  }
2601
2602  /* for now we skip admin messages. */
2603  if (owl_message_is_type_admin(m)
2604      || owl_message_is_loginout(m)
2605      || !owl_message_is_type_zephyr(m)) {
2606    owl_function_makemsg("smartzpunt doesn't support this message type.");
2607    return;
2608  }
2609
2610  mclass = owl_message_get_class(m);
2611  minst = owl_message_get_instance(m);
2612  if (!mclass || !*mclass || *mclass==' '
2613      || (!strcasecmp(mclass, "message") && !strcasecmp(minst, "personal"))
2614      || (type && (!minst || !*minst|| *minst==' '))) {
2615    owl_function_makemsg("smartzpunt can't safely do this for <%s,%s>",
2616                         mclass, minst);
2617  } else {
2618    cmdprefix = "start-command zpunt ";
2619    cmd = owl_malloc(strlen(cmdprefix)+strlen(mclass)+strlen(minst)+3);
2620    strcpy(cmd, cmdprefix);
2621    strcat(cmd, mclass);
2622    if (type) {
2623      strcat(cmd, " ");
2624      strcat(cmd, minst);
2625    } else {
2626      strcat(cmd, " *");
2627    }
2628    owl_function_command(cmd);
2629    owl_free(cmd);
2630  }
2631}
2632
2633
2634
2635void owl_function_color_current_filter(char *color)
2636{
2637  owl_filter *f;
2638  char *name;
2639
2640  name=owl_view_get_filtname(owl_global_get_current_view(&g));
2641  f=owl_global_get_filter(&g, name);
2642  if (!f) {
2643    owl_function_makemsg("Unknown filter");
2644    return;
2645  }
2646
2647  /* don't touch the all filter */
2648  if (!strcmp(name, "all")) {
2649    owl_function_makemsg("You may not change the 'all' filter.");
2650    return;
2651  }
2652
2653  /* deal with the case of trying change the filter color */
2654  owl_filter_set_color(f, owl_util_string_to_color(color));
2655  owl_global_set_needrefresh(&g);
2656  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2657}
2658
2659void owl_function_show_colors()
2660{
2661  owl_fmtext fm;
2662
2663  owl_fmtext_init_null(&fm);
2664  owl_fmtext_append_normal_color(&fm, "default\n", OWL_COLOR_DEFAULT);
2665  owl_fmtext_append_normal_color(&fm, "red\n", OWL_COLOR_RED);
2666  owl_fmtext_append_normal_color(&fm, "green\n", OWL_COLOR_GREEN);
2667  owl_fmtext_append_normal_color(&fm, "yellow\n", OWL_COLOR_YELLOW);
2668  owl_fmtext_append_normal_color(&fm, "blue\n", OWL_COLOR_BLUE);
2669  owl_fmtext_append_normal_color(&fm, "magenta\n", OWL_COLOR_MAGENTA);
2670  owl_fmtext_append_normal_color(&fm, "cyan\n", OWL_COLOR_CYAN);
2671  owl_fmtext_append_normal_color(&fm, "white\n", OWL_COLOR_WHITE);
2672
2673  owl_function_popless_fmtext(&fm);
2674  owl_fmtext_free(&fm);
2675}
2676
2677/* add the given class, inst, recip to the punt list for filtering.
2678 *   if direction==0 then punt
2679 *   if direction==1 then unpunt
2680 */
2681void owl_function_zpunt(char *class, char *inst, char *recip, int direction)
2682{
2683  owl_filter *f;
2684  owl_list *fl;
2685  char *buff;
2686  int ret, i, j;
2687
2688  fl=owl_global_get_puntlist(&g);
2689
2690  /* first, create the filter */
2691  f=malloc(sizeof(owl_filter));
2692  buff=malloc(strlen(class)+strlen(inst)+strlen(recip)+100);
2693  strcpy(buff, "class");
2694  if (!strcmp(class, "*")) {
2695    strcat(buff, " .*");
2696  } else {
2697    sprintf(buff, "%s ^%s$", buff, class);
2698  }
2699  if (!strcmp(inst, "*")) {
2700    strcat(buff, " and instance .*");
2701  } else {
2702    sprintf(buff, "%s and instance ^%s$", buff, inst);
2703  }
2704  if (strcmp(recip, "*")) {
2705    sprintf(buff, "%s and recipient ^%s$", buff, recip);
2706  }
2707 
2708  owl_function_debugmsg("About to filter %s", buff);
2709  ret=owl_filter_init_fromstring(f, "punt-filter", buff);
2710  owl_free(buff);
2711  if (ret) {
2712    owl_function_makemsg("Error creating filter for zpunt");
2713    owl_filter_free(f);
2714    return;
2715  }
2716
2717  /* Check for an identical filter */
2718  j=owl_list_get_size(fl);
2719  for (i=0; i<j; i++) {
2720    if (owl_filter_equiv(f, owl_list_get_element(fl, i))) {
2721      /* if we're punting, then just silently bow out on this duplicate */
2722      if (direction==0) {
2723        owl_filter_free(f);
2724        return;
2725      }
2726
2727      /* if we're unpunting, then remove this filter from the puntlist */
2728      if (direction==1) {
2729        owl_filter_free(owl_list_get_element(fl, i));
2730        owl_list_remove_element(fl, i);
2731        return;
2732      }
2733    }
2734  }
2735
2736  /* If we're punting, add the filter to the global punt list */
2737  if (direction==0) {
2738    owl_list_append_element(fl, f);
2739  }
2740}
2741
2742void owl_function_activate_keymap(char *keymap)
2743{
2744  if (!owl_keyhandler_activate(owl_global_get_keyhandler(&g), keymap)) {
2745    owl_function_makemsg("Unable to activate keymap '%s'", keymap);
2746  }
2747}
2748
2749
2750void owl_function_show_keymaps()
2751{
2752  owl_list l;
2753  owl_fmtext fm;
2754  owl_keymap *km;
2755  owl_keyhandler *kh;
2756  int i, numkm;
2757  char *kmname;
2758
2759  kh = owl_global_get_keyhandler(&g);
2760  owl_fmtext_init_null(&fm);
2761  owl_fmtext_append_bold(&fm, "Keymaps:   ");
2762  owl_fmtext_append_normal(&fm, "(use 'show keymap <name>' for details)\n");
2763  owl_keyhandler_get_keymap_names(kh, &l);
2764  owl_fmtext_append_list(&fm, &l, "\n", owl_function_keymap_summary);
2765  owl_fmtext_append_normal(&fm, "\n");
2766
2767  numkm = owl_list_get_size(&l);
2768  for (i=0; i<numkm; i++) {
2769    kmname = owl_list_get_element(&l, i);
2770    km = owl_keyhandler_get_keymap(kh, kmname);
2771    owl_fmtext_append_bold(&fm, "\n\n----------------------------------------------------------------------------------------------------\n\n");
2772    owl_keymap_get_details(km, &fm);   
2773  }
2774  owl_fmtext_append_normal(&fm, "\n");
2775 
2776  owl_function_popless_fmtext(&fm);
2777  owl_keyhandler_keymap_namelist_free(&l);
2778  owl_fmtext_free(&fm);
2779}
2780
2781char *owl_function_keymap_summary(void *name)
2782{
2783  owl_keymap *km
2784    = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
2785  if (km) return owl_keymap_summary(km);
2786  else return(NULL);
2787}
2788
2789/* TODO: implement for real */
2790void owl_function_show_keymap(char *name)
2791{
2792  owl_fmtext fm;
2793  owl_keymap *km;
2794
2795  owl_fmtext_init_null(&fm);
2796  km = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
2797  if (km) {
2798    owl_keymap_get_details(km, &fm);
2799  } else {
2800    owl_fmtext_append_normal(&fm, "No such keymap...\n");
2801  } 
2802  owl_function_popless_fmtext(&fm);
2803  owl_fmtext_free(&fm);
2804}
2805
2806void owl_function_help_for_command(char *cmdname)
2807{
2808  owl_fmtext fm;
2809
2810  owl_fmtext_init_null(&fm);
2811  owl_cmd_get_help(owl_global_get_cmddict(&g), cmdname, &fm);
2812  owl_function_popless_fmtext(&fm); 
2813  owl_fmtext_free(&fm);
2814}
2815
2816void owl_function_search_start(char *string, int direction)
2817{
2818  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
2819  owl_global_set_search_active(&g, string);
2820  owl_function_search_helper(0, direction);
2821}
2822
2823void owl_function_search_continue(int direction)
2824{
2825  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
2826  owl_function_search_helper(1, direction);
2827}
2828
2829void owl_function_search_helper(int mode, int direction)
2830{
2831  /* move to a message that contains the string.  If direction is
2832   * OWL_DIRECTION_DOWNWARDS then search fowards, if direction is
2833   * OWL_DIRECTION_UPWARDS then search backwards.
2834   *
2835   * If mode==0 then it will stay on the current message if it
2836   * contains the string.
2837   */
2838
2839  owl_view *v;
2840  int viewsize, i, curmsg, start;
2841  owl_message *m;
2842
2843  v=owl_global_get_current_view(&g);
2844  viewsize=owl_view_get_size(v);
2845  curmsg=owl_global_get_curmsg(&g);
2846 
2847  if (viewsize==0) {
2848    owl_function_makemsg("No messages present");
2849    return;
2850  }
2851
2852  if (mode==0) {
2853    start=curmsg;
2854  } else if (direction==OWL_DIRECTION_DOWNWARDS) {
2855    start=curmsg+1;
2856  } else {
2857    start=curmsg-1;
2858  }
2859
2860  /* bounds check */
2861  if (start>=viewsize || start<0) {
2862    owl_function_makemsg("No further matches found");
2863    return;
2864  }
2865
2866  for (i=start; i<viewsize && i>=0;) {
2867    m=owl_view_get_element(v, i);
2868    if (owl_message_search(m, owl_global_get_search_string(&g))) {
2869      owl_global_set_curmsg(&g, i);
2870      owl_function_calculate_topmsg(direction);
2871      owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2872      if (direction==OWL_DIRECTION_DOWNWARDS) {
2873        owl_global_set_direction_downwards(&g);
2874      } else {
2875        owl_global_set_direction_upwards(&g);
2876      }
2877      return;
2878    }
2879    if (direction==OWL_DIRECTION_DOWNWARDS) {
2880      i++;
2881    } else {
2882      i--;
2883    }
2884  }
2885  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2886  owl_function_makemsg("No matches found");
2887}
2888
2889
2890/* strips formatting from ztext and returns the unformatted text.
2891 * caller is responsible for freeing. */
2892char *owl_function_ztext_stylestrip(char *zt)
2893{
2894  owl_fmtext fm;
2895  char *plaintext;
2896
2897  owl_fmtext_init_null(&fm);
2898  owl_fmtext_append_ztext(&fm, zt);
2899  plaintext = owl_fmtext_print_plain(&fm);
2900  owl_fmtext_free(&fm);
2901  return(plaintext);
2902}
2903
2904/* Popup a buddylisting.  If file is NULL use the default .anyone */
2905void owl_function_buddylist(int aim, int zephyr, char *file)
2906{
2907  int i, j, idle;
2908  owl_fmtext fm;
2909  owl_buddylist *b;
2910  char *foo, *timestr;
2911#ifdef HAVE_LIBZEPHYR
2912  char *ourfile, *tmp, buff[LINE], *line;
2913  ZLocations_t location[200];
2914  FILE *f;
2915  int numlocs, ret;
2916#endif
2917
2918  owl_fmtext_init_null(&fm);
2919
2920  if (aim && owl_global_is_aimloggedin(&g)) {
2921    b=owl_global_get_buddylist(&g);
2922
2923    owl_fmtext_append_bold(&fm, "AIM users logged in:\n");
2924    j=owl_buddylist_get_size(b);
2925    for (i=0; i<j; i++) {
2926      idle=owl_buddylist_get_idletime(b, i);
2927      if (idle!=0) {
2928        timestr=owl_util_minutes_to_timestr(idle);
2929      } else {
2930        timestr=owl_strdup("");
2931      }
2932      foo=owl_sprintf("  %-15.15s %-12.12s\n",
2933                      owl_buddylist_get_buddy(b, i),
2934                      timestr);
2935      owl_fmtext_append_normal(&fm, foo);
2936      owl_free(timestr);
2937      owl_free(foo);
2938    }
2939  }
2940
2941#ifdef HAVE_LIBZEPHYR
2942  if (zephyr) {
2943    if (file==NULL) {
2944      tmp=owl_global_get_homedir(&g);
2945      if (!tmp) {
2946        owl_function_makemsg("Could not determine home directory");
2947        return;
2948      }
2949      ourfile=owl_malloc(strlen(tmp)+50);
2950      sprintf(ourfile, "%s/.anyone", owl_global_get_homedir(&g));
2951    } else {
2952      ourfile=owl_strdup(file);
2953    }
2954   
2955    f=fopen(ourfile, "r");
2956    if (!f) {
2957      owl_function_makemsg("Error opening file %s: %s",
2958                           ourfile,
2959                           strerror(errno) ? strerror(errno) : "");
2960      return;
2961    }
2962
2963    owl_fmtext_append_bold(&fm, "Zephyr users logged in:\n");
2964   
2965    while (fgets(buff, LINE, f)!=NULL) {
2966      /* ignore comments, blank lines etc. */
2967      if (buff[0]=='#') continue;
2968      if (buff[0]=='\n') continue;
2969      if (buff[0]=='\0') continue;
2970     
2971      /* strip the \n */
2972      buff[strlen(buff)-1]='\0';
2973     
2974      /* ingore from # on */
2975      tmp=strchr(buff, '#');
2976      if (tmp) tmp[0]='\0';
2977     
2978      /* ingore from SPC */
2979      tmp=strchr(buff, ' ');
2980      if (tmp) tmp[0]='\0';
2981     
2982      /* stick on the local realm. */
2983      if (!strchr(buff, '@')) {
2984        strcat(buff, "@");
2985        strcat(buff, ZGetRealm());
2986      }
2987     
2988      ret=ZLocateUser(buff, &numlocs, ZAUTH);
2989      if (ret!=ZERR_NONE) {
2990        owl_function_makemsg("Error getting location for %s", buff);
2991        continue;
2992      }
2993     
2994      numlocs=200;
2995      ret=ZGetLocations(location, &numlocs);
2996      if (ret==0) {
2997        for (i=0; i<numlocs; i++) {
2998          line=malloc(strlen(location[i].host)+strlen(location[i].time)+strlen(location[i].tty)+100);
2999          tmp=short_zuser(buff);
3000          sprintf(line, "  %-10.10s %-24.24s %-12.12s  %20.20s\n",
3001                  tmp,
3002                  location[i].host,
3003                  location[i].tty,
3004                  location[i].time);
3005          owl_fmtext_append_normal(&fm, line);
3006          owl_free(tmp);
3007        }
3008        if (numlocs>=200) {
3009          owl_fmtext_append_normal(&fm, "  Too many locations found for this user, truncating.\n");
3010        }
3011      }
3012    }
3013    fclose(f);
3014    owl_free(ourfile);
3015  }
3016#endif
3017 
3018  owl_function_popless_fmtext(&fm);
3019  owl_fmtext_free(&fm);
3020}
3021
3022void owl_function_dump(char *filename) 
3023{
3024  int i, j, count;
3025  owl_message *m;
3026  owl_view *v;
3027  FILE *file;
3028  /* struct stat sbuf; */
3029
3030  v=owl_global_get_current_view(&g);
3031
3032  /* in the future make it ask yes/no */
3033  /*
3034  ret=stat(filename, &sbuf);
3035  if (!ret) {
3036    ret=owl_function_askyesno("File exists, continue? [Y/n]");
3037    if (!ret) return;
3038  }
3039  */
3040
3041  file=fopen(filename, "w");
3042  if (!file) {
3043    owl_function_makemsg("Error opening file");
3044    return;
3045  }
3046
3047  count=0;
3048  j=owl_view_get_size(v);
3049  for (i=0; i<j; i++) {
3050    m=owl_view_get_element(v, i);
3051    fputs(owl_message_get_text(m), file);
3052  }
3053  fclose(file);
3054}
3055
3056
3057
3058void owl_function_do_newmsgproc(void)
3059{
3060  if (owl_global_get_newmsgproc(&g) && strcmp(owl_global_get_newmsgproc(&g), "")) {
3061    /* if there's a process out there, we need to check on it */
3062    if (owl_global_get_newmsgproc_pid(&g)) {
3063      owl_function_debugmsg("Checking on newmsgproc pid==%i", owl_global_get_newmsgproc_pid(&g));
3064      owl_function_debugmsg("Waitpid return is %i", waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG));
3065      waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG);
3066      if (waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG)==-1) {
3067        /* it exited */
3068        owl_global_set_newmsgproc_pid(&g, 0);
3069        owl_function_debugmsg("newmsgproc exited");
3070      } else {
3071        owl_function_debugmsg("newmsgproc did not exit");
3072      }
3073    }
3074   
3075    /* if it exited, fork & exec a new one */
3076    if (owl_global_get_newmsgproc_pid(&g)==0) {
3077      int i, myargc;
3078      i=fork();
3079      if (i) {
3080        /* parent set the child's pid */
3081        owl_global_set_newmsgproc_pid(&g, i);
3082        owl_function_debugmsg("I'm the parent and I started a new newmsgproc with pid %i", i);
3083      } else {
3084        /* child exec's the program */
3085        char **parsed;
3086        parsed=owl_parseline(owl_global_get_newmsgproc(&g), &myargc);
3087        if (myargc < 0) {
3088          owl_function_debugmsg("Could not parse newmsgproc '%s': unbalanced quotes?", owl_global_get_newmsgproc(&g));
3089        }
3090        if (myargc <= 0) {
3091          _exit(127);
3092        }
3093        parsed=realloc(parsed, sizeof(*parsed) * (myargc+1));
3094        parsed[myargc] = NULL;
3095       
3096        owl_function_debugmsg("About to exec \"%s\" with %d arguments", parsed[0], myargc);
3097       
3098        execvp(parsed[0], parsed);
3099       
3100       
3101        /* was there an error exec'ing? */
3102        owl_function_debugmsg("Cannot run newmsgproc '%s': cannot exec '%s': %s", 
3103                              owl_global_get_newmsgproc(&g), parsed[0], strerror(errno));
3104        _exit(127);
3105      }
3106    }
3107  }
3108}
3109
3110/* print the xterm escape sequence to raise the window */
3111void owl_function_xterm_raise(void)
3112{
3113  printf("\033[5t");
3114}
3115
3116/* print the xterm escape sequence to deiconify the window */
3117void owl_function_xterm_deiconify(void)
3118{
3119  printf("\033[1t");
3120}
3121
3122/* Add the specified command to the startup file.  Eventually this
3123 * should be clever, and rewriting settings that will obviosly
3124 * override earlier settings with 'set' 'bindkey' and 'alias'
3125 * commands.  For now though we just remove any line that would
3126 * duplicate this one and then append this line to the end of
3127 * startupfile.
3128 */
3129void owl_function_addstartup(char *buff)
3130{
3131  FILE *file;
3132  char *filename;
3133
3134  filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
3135  file=fopen(filename, "a");
3136  if (!file) {
3137    owl_function_makemsg("Error opening startupfile for new command");
3138    owl_free(filename);
3139    return;
3140  }
3141
3142  /* delete earlier copies */
3143  owl_util_file_deleteline(filename, buff, 1);
3144  owl_free(filename);
3145
3146  /* add this line */
3147  fprintf(file, "%s\n", buff);
3148
3149  fclose(file);
3150}
3151
3152/* Remove the specified command from the startup file. */
3153void owl_function_delstartup(char *buff)
3154{
3155  char *filename;
3156  filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
3157  owl_util_file_deleteline(filename, buff, 1);
3158  owl_free(filename);
3159}
3160
3161void owl_function_execstartup(void)
3162{
3163  FILE *file;
3164  char *filename;
3165  char buff[LINE];
3166
3167  filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
3168  file=fopen(filename, "r");
3169  owl_free(filename);
3170  if (!file) {
3171    /* just fail silently if it doesn't exist */
3172    return;
3173  }
3174  while (fgets(buff, LINE, file)!=NULL) {
3175    buff[strlen(buff)-1]='\0';
3176    owl_function_command(buff);
3177  }
3178  fclose(file);
3179}
3180
3181
3182void owl_function_change_style(owl_view *v, char *stylename)
3183{
3184  owl_style *s;
3185
3186  s=owl_global_get_style_by_name(&g, stylename);
3187  if (!s) {
3188    owl_function_makemsg("No style named %s", stylename);
3189    return;
3190  }
3191  owl_view_set_style(v, s);
3192  owl_messagelist_invalidate_formats(owl_global_get_msglist(&g));
3193  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
3194  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3195 
3196}
3197
3198void owl_function_toggleoneline()
3199{
3200  owl_view *v;
3201  owl_style *s;
3202
3203  v=owl_global_get_current_view(&g);
3204  s=owl_view_get_style(v);
3205
3206  if (!owl_style_matches_name(s, "oneline")) {
3207    owl_function_change_style(v, "oneline");
3208  } else {
3209    owl_function_change_style(v, owl_global_get_default_style(&g));
3210  }
3211
3212  owl_messagelist_invalidate_formats(owl_global_get_msglist(&g));
3213  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
3214  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3215}
Note: See TracBrowser for help on using the repository browser.