source: functions.c @ 0154e2d

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