source: functions.c @ 789462a

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