source: functions.c @ 95474d7

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