source: functions.c @ 740d5f7

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