source: functions.c @ ca9142e

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