source: functions.c @ 723c427

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