source: functions.c @ e6449bc

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