source: functions.c @ debb15d

barnowl_perlaimdebianowlrelease-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since debb15d was debb15d, checked in by James M. Kretchmar <kretch@mit.edu>, 17 years ago
Added 'show license'
  • Property mode set to 100644
File size: 94.5 KB
Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <signal.h>
5#include <string.h>
6#include <time.h>
7#include <sys/types.h>
8#include <sys/stat.h>
9#include <sys/wait.h>
10#include <errno.h>
11#include <signal.h>
12#include "owl.h"
13
14static const char fileIdent[] = "$Id$";
15
16void owl_function_noop(void)
17{
18  return;
19}
20
21char *owl_function_command(char *cmdbuff)
22{
23  owl_function_debugmsg("executing command: %s", cmdbuff);
24  return owl_cmddict_execute(owl_global_get_cmddict(&g), 
25                             owl_global_get_context(&g), cmdbuff);
26}
27
28void owl_function_command_norv(char *cmdbuff)
29{
30  char *rv;
31  rv=owl_function_command(cmdbuff);
32  if (rv) owl_free(rv);
33}
34
35void owl_function_command_alias(char *alias_from, char *alias_to)
36{
37  owl_cmddict_add_alias(owl_global_get_cmddict(&g), alias_from, alias_to);
38}
39
40owl_cmd *owl_function_get_cmd(char *name)
41{
42  return owl_cmddict_find(owl_global_get_cmddict(&g), name);
43}
44
45void owl_function_show_commands()
46{
47  owl_list l;
48  owl_fmtext fm;
49
50  owl_fmtext_init_null(&fm);
51  owl_fmtext_append_bold(&fm, "Commands:  ");
52  owl_fmtext_append_normal(&fm, "(use 'show command <name>' for details)\n");
53  owl_cmddict_get_names(owl_global_get_cmddict(&g), &l);
54  owl_fmtext_append_list(&fm, &l, "\n", owl_function_cmd_describe);
55  owl_fmtext_append_normal(&fm, "\n");
56  owl_function_popless_fmtext(&fm);
57  owl_cmddict_namelist_free(&l);
58  owl_fmtext_free(&fm);
59}
60
61void owl_function_show_view(char *viewname)
62{
63  owl_view *v;
64  owl_fmtext fm;
65
66  /* we only have the one view right now */
67  v=owl_global_get_current_view(&g);
68  if (viewname && strcmp(viewname, owl_view_get_name(v))) {
69    owl_function_error("No view named '%s'", viewname);
70    return;
71  }
72
73  owl_fmtext_init_null(&fm);
74  owl_view_to_fmtext(v, &fm);
75  owl_function_popless_fmtext(&fm);
76  owl_fmtext_free(&fm);
77}
78
79void owl_function_show_styles() {
80  owl_list l;
81  owl_fmtext fm;
82
83  owl_fmtext_init_null(&fm);
84  owl_fmtext_append_bold(&fm, "Styles:\n");
85  owl_global_get_style_names(&g, &l);
86  owl_fmtext_append_list(&fm, &l, "\n", owl_function_style_describe);
87  owl_fmtext_append_normal(&fm, "\n");
88  owl_function_popless_fmtext(&fm);
89  owl_list_free_all(&l, owl_free);
90  owl_fmtext_free(&fm);
91}
92
93char *owl_function_style_describe(void *name) {
94  char *desc, *s;
95  owl_style *style;
96  style = owl_global_get_style_by_name(&g, name);
97  if (style) {
98    desc = owl_style_get_description(style);
99  } else {
100    desc = "???";
101  }
102  s = owl_sprintf("%-20s - %s%s", name, 
103                  0==owl_style_validate(style)?"":"[INVALID] ",
104                  desc);
105  return s;
106}
107
108char *owl_function_cmd_describe(void *name)
109{
110  owl_cmd *cmd = owl_cmddict_find(owl_global_get_cmddict(&g), name);
111  if (cmd) return owl_cmd_describe(cmd);
112  else return(NULL);
113}
114
115void owl_function_show_command(char *name)
116{
117  owl_function_help_for_command(name);
118}
119
120void owl_function_show_license()
121{
122  char *text;
123
124  text=""
125    "Owl version " OWL_VERSION_STRING "\n"
126    "Copyright (c) 2004 James Kretchmar. All rights reserved.\n"
127    "\n"
128    "Redistribution and use in source and binary forms, with or without\n"
129    "modification, are permitted provided that the following conditions are\n"
130    "met:\n"
131    "\n"
132    "   * Redistributions of source code must retain the above copyright\n"
133    "     notice, this list of conditions and the following disclaimer.\n"
134    "\n"
135    "   * Redistributions in binary form must reproduce the above copyright\n"
136    "     notice, this list of conditions and the following disclaimer in\n"
137    "     the documentation and/or other materials provided with the\n"
138    "     distribution.\n"
139    "\n"
140    "   * Redistributions in any form must be accompanied by information on\n"
141    "     how to obtain complete source code for the Owl software and any\n"
142    "     accompanying software that uses the Owl software. The source code\n"
143    "     must either be included in the distribution or be available for no\n"
144    "     more than the cost of distribution plus a nominal fee, and must be\n"
145    "     freely redistributable under reasonable conditions. For an\n"
146    "     executable file, complete source code means the source code for\n"
147    "     all modules it contains. It does not include source code for\n"
148    "     modules or files that typically accompany the major components of\n"
149    "     the operating system on which the executable file runs.\n"
150    "\n"
151    "THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n"
152    "IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n"
153    "WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR\n"
154    "NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE\n"
155    "LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n"
156    "CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n"
157    "SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR\n"
158    "BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n"
159    "WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n"
160    "OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\n"
161    "IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n";
162  owl_function_popless_text(text);
163}
164
165void owl_function_adminmsg(char *header, char *body)
166{
167  owl_message *m;
168  int followlast;
169
170  followlast=owl_global_should_followlast(&g);
171  m=owl_malloc(sizeof(owl_message));
172  owl_message_create_admin(m, header, body);
173  owl_messagelist_append_element(owl_global_get_msglist(&g), m);
174  owl_view_consider_message(owl_global_get_current_view(&g), m);
175
176  if (followlast) owl_function_lastmsg_noredisplay();
177
178  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
179  if (owl_popwin_is_active(owl_global_get_popwin(&g))) {
180    owl_popwin_refresh(owl_global_get_popwin(&g));
181  }
182 
183  wnoutrefresh(owl_global_get_curs_recwin(&g));
184  owl_global_set_needrefresh(&g);
185}
186
187void owl_function_make_outgoing_zephyr(char *body, char *zwriteline, char *zsig)
188{
189  owl_message *m;
190  int followlast;
191  owl_zwrite z;
192 
193  followlast=owl_global_should_followlast(&g);
194
195  /* create a zwrite for the purpose of filling in other message fields */
196  owl_zwrite_create_from_line(&z, zwriteline);
197
198  /* create the message */
199  m=owl_malloc(sizeof(owl_message));
200  owl_message_create_from_zwriteline(m, zwriteline, body, zsig);
201
202  /* add it to the global list and current view */
203  owl_messagelist_append_element(owl_global_get_msglist(&g), m);
204  owl_view_consider_message(owl_global_get_current_view(&g), m);
205
206  if (followlast) owl_function_lastmsg_noredisplay();
207
208  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
209  if (owl_popwin_is_active(owl_global_get_popwin(&g))) {
210    owl_popwin_refresh(owl_global_get_popwin(&g));
211  }
212 
213  wnoutrefresh(owl_global_get_curs_recwin(&g));
214  owl_global_set_needrefresh(&g);
215  owl_zwrite_free(&z);
216}
217
218int owl_function_make_outgoing_aim(char *body, char *to)
219{
220  owl_message *m;
221  int followlast;
222
223
224  if (!owl_global_is_aimloggedin(&g)) {
225    return(-1);
226  }
227 
228  followlast=owl_global_should_followlast(&g);
229
230  /* create the message */
231  m=owl_malloc(sizeof(owl_message));
232  owl_message_create_aim(m,
233                         owl_global_get_aim_screenname(&g),
234                         to,
235                         body,
236                         OWL_MESSAGE_DIRECTION_OUT,
237                         0);
238
239  /* add it to the global list and current view */
240  owl_messagelist_append_element(owl_global_get_msglist(&g), m);
241  owl_view_consider_message(owl_global_get_current_view(&g), m);
242
243  if (followlast) owl_function_lastmsg_noredisplay();
244
245  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
246  if (owl_popwin_is_active(owl_global_get_popwin(&g))) {
247    owl_popwin_refresh(owl_global_get_popwin(&g));
248  }
249 
250  wnoutrefresh(owl_global_get_curs_recwin(&g));
251  owl_global_set_needrefresh(&g);
252  return(0);
253}
254
255int owl_function_make_outgoing_loopback(char *body)
256{
257  owl_message *m;
258  int followlast;
259
260  followlast=owl_global_should_followlast(&g);
261
262  /* create the message */
263  m=owl_malloc(sizeof(owl_message));
264  owl_message_create_loopback(m, body);
265  owl_message_set_direction_out(m);
266
267  /* add it to the global list and current view */
268  owl_messagelist_append_element(owl_global_get_msglist(&g), m);
269  owl_view_consider_message(owl_global_get_current_view(&g), m);
270
271  if (followlast) owl_function_lastmsg_noredisplay();
272
273  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
274  if (owl_popwin_is_active(owl_global_get_popwin(&g))) {
275    owl_popwin_refresh(owl_global_get_popwin(&g));
276  }
277 
278  wnoutrefresh(owl_global_get_curs_recwin(&g));
279  owl_global_set_needrefresh(&g);
280  return(0);
281}
282
283void owl_function_zwrite_setup(char *line)
284{
285  owl_editwin *e;
286  char buff[1024];
287  owl_zwrite z;
288  int ret;
289
290  /* check the arguments */
291  ret=owl_zwrite_create_from_line(&z, line);
292  if (ret) {
293    owl_function_error("Error in zwrite arugments");
294    owl_zwrite_free(&z);
295    return;
296  }
297
298  /* send a ping if necessary */
299  if (owl_global_is_txping(&g)) {
300    owl_zwrite_send_ping(&z);
301  }
302  owl_zwrite_free(&z);
303
304  /* create and setup the editwin */
305  e=owl_global_get_typwin(&g);
306  owl_editwin_new_style(e, OWL_EDITWIN_STYLE_MULTILINE, owl_global_get_msg_history(&g));
307
308  if (!owl_global_get_lockout_ctrld(&g)) {
309    owl_function_makemsg("Type your zephyr below.  End with ^D or a dot on a line by itself.  ^C will quit.");
310  } else {
311    owl_function_makemsg("Type your zephyr below.  End with a dot on a line by itself.  ^C will quit.");
312  }
313
314  owl_editwin_clear(e);
315  owl_editwin_set_dotsend(e);
316  strcpy(buff, "----> ");
317  strcat(buff, line);
318  strcat(buff, "\n");
319  owl_editwin_set_locktext(e, buff);
320
321  /* make it active */
322  owl_global_set_typwin_active(&g);
323
324  owl_global_set_buffercommand(&g, line);
325}
326
327void owl_function_aimwrite_setup(char *line)
328{
329  owl_editwin *e;
330  char buff[1024];
331
332  /* check the arguments */
333
334  /* create and setup the editwin */
335  e=owl_global_get_typwin(&g);
336  owl_editwin_new_style(e, OWL_EDITWIN_STYLE_MULTILINE, owl_global_get_msg_history(&g));
337
338  if (!owl_global_get_lockout_ctrld(&g)) {
339    owl_function_makemsg("Type your message below.  End with ^D or a dot on a line by itself.  ^C will quit.");
340  } else {
341    owl_function_makemsg("Type your message below.  End with a dot on a line by itself.  ^C will quit.");
342  }
343
344  owl_editwin_clear(e);
345  owl_editwin_set_dotsend(e);
346  strcpy(buff, "----> ");
347  strcat(buff, line);
348  strcat(buff, "\n");
349  owl_editwin_set_locktext(e, buff);
350
351  /* make it active */
352  owl_global_set_typwin_active(&g);
353
354  owl_global_set_buffercommand(&g, line);
355}
356
357void owl_function_loopwrite_setup()
358{
359  owl_editwin *e;
360
361  /* create and setup the editwin */
362  e=owl_global_get_typwin(&g);
363  owl_editwin_new_style(e, OWL_EDITWIN_STYLE_MULTILINE, owl_global_get_msg_history(&g));
364
365  if (!owl_global_get_lockout_ctrld(&g)) {
366    owl_function_makemsg("Type your message below.  End with ^D or a dot on a line by itself.  ^C will quit.");
367  } else {
368    owl_function_makemsg("Type your message below.  End with a dot on a line by itself.  ^C will quit.");
369  }
370
371  owl_editwin_clear(e);
372  owl_editwin_set_dotsend(e);
373  owl_editwin_set_locktext(e, "----> loopwrite\n");
374
375  /* make it active */
376  owl_global_set_typwin_active(&g);
377
378  owl_global_set_buffercommand(&g, "loopwrite");
379}
380
381/* send, log and display an outgoing zephyr.  If 'msg' is NULL
382 * the message is expected to be set from the zwrite line itself
383 */
384void owl_function_zwrite(char *line, char *msg)
385{
386  owl_zwrite z;
387  int i, j;
388  char *mymsg;
389
390  /* create the zwrite and send the message */
391  owl_zwrite_create_from_line(&z, line);
392  if (msg) {
393    owl_zwrite_set_message(&z, msg);
394  }
395
396  owl_zwrite_send_message(&z);
397  owl_function_makemsg("Waiting for ack...");
398
399  mymsg=owl_zwrite_get_message(&z);
400
401  /* display the message as an outgoing message in the receive window */
402  if (owl_global_is_displayoutgoing(&g) && owl_zwrite_is_personal(&z)) {
403    owl_function_make_outgoing_zephyr(mymsg, line, owl_zwrite_get_zsig(&z));
404  }
405
406  /* log it if we have logging turned on */
407  if (owl_global_is_logging(&g) && owl_zwrite_is_personal(&z)) {
408    j=owl_zwrite_get_numrecips(&z);
409    for (i=0; i<j; i++) {
410      owl_log_outgoing_zephyr(owl_zwrite_get_recip_n(&z, i), mymsg);
411    }
412  }
413
414  /* free the zwrite */
415  owl_zwrite_free(&z);
416}
417
418/* send, log and display an outgoing zcrypt zephyr.  If 'msg' is NULL
419 * the message is expected to be set from the zwrite line itself
420 */
421void owl_function_zcrypt(char *line, char *msg)
422{
423  owl_zwrite z;
424  int i, j;
425  char *mymsg;
426  char *cryptmsg;
427#ifdef OWL_ENABLE_ZCRYPT
428  int ret;
429#endif
430
431  /* create the zwrite and send the message */
432  owl_zwrite_create_from_line(&z, line);
433  if (msg) {
434    owl_zwrite_set_message(&z, msg);
435  }
436
437  mymsg=owl_zwrite_get_message(&z);
438#ifdef OWL_ENABLE_ZCRYPT
439  cryptmsg=owl_malloc(strlen(mymsg)*4);
440  ret=owl_zcrypt_encrypt(cryptmsg, mymsg, owl_zwrite_get_class(&z), owl_zwrite_get_instance(&z));
441  if (ret) {
442    owl_function_error("Error in zcrypt, possibly no key found.  Message not sent.");
443    owl_function_beep();
444    owl_free(cryptmsg);
445    return;
446  }
447#else
448  cryptmsg=owl_strdup(mymsg);
449#endif
450
451  owl_zwrite_set_message(&z, cryptmsg);
452  owl_zwrite_set_opcode(&z, "crypt");
453  mymsg=cryptmsg;
454   
455  owl_zwrite_send_message(&z);
456  owl_function_makemsg("Waiting for ack...");
457
458  /* display the message as an outgoing message in the receive window */
459  if (owl_global_is_displayoutgoing(&g) && owl_zwrite_is_personal(&z)) {
460    owl_function_make_outgoing_zephyr(mymsg, line, owl_zwrite_get_zsig(&z));
461  }
462
463  /* log it if we have logging turned on */
464  if (owl_global_is_logging(&g) && owl_zwrite_is_personal(&z)) {
465    j=owl_zwrite_get_numrecips(&z);
466    for (i=0; i<j; i++) {
467      owl_log_outgoing_zephyr(owl_zwrite_get_recip_n(&z, i), mymsg);
468    }
469  }
470
471  /* free the zwrite */
472  owl_free(cryptmsg);
473  owl_zwrite_free(&z);
474}
475
476void owl_function_aimwrite(char *to)
477{
478  int ret;
479  char *msg, *format_msg;
480
481  /* make a formatted copy of the message */
482  msg=owl_editwin_get_text(owl_global_get_typwin(&g));
483  format_msg=owl_strdup(msg);
484  owl_text_wordunwrap(format_msg);
485 
486  /* send the message */
487  ret=owl_aim_send_im(to, format_msg);
488  if (!ret) {
489    owl_function_makemsg("AIM message sent.");
490  } else {
491    owl_function_error("Could not send AIM message.");
492  }
493
494  /* display the message as an outgoing message in the receive window */
495  if (owl_global_is_displayoutgoing(&g)) {
496    owl_function_make_outgoing_aim(msg, to);
497  }
498
499  /* log it if we have logging turned on */
500  if (owl_global_is_logging(&g)) {
501    owl_log_outgoing_aim(to, msg);
502  }
503
504  owl_free(format_msg);
505}
506
507void owl_function_send_aimawymsg(char *to, char *msg)
508{
509  int ret;
510  char *format_msg;
511
512  /* make a formatted copy of the message */
513  format_msg=owl_strdup(msg);
514  owl_text_wordunwrap(format_msg);
515 
516  /* send the message */
517  ret=owl_aim_send_awaymsg(to, format_msg);
518  if (!ret) {
519    /* owl_function_makemsg("AIM message sent."); */
520  } else {
521    owl_function_error("Could not send AIM message.");
522  }
523
524  /* display the message as an outgoing message in the receive window */
525  if (owl_global_is_displayoutgoing(&g)) {
526    owl_function_make_outgoing_aim(msg, to);
527  }
528
529  /* log it if we have logging turned on */
530  if (owl_global_is_logging(&g)) {
531    owl_log_outgoing_aim(to, msg);
532  }
533
534  owl_free(format_msg);
535}
536
537void owl_function_loopwrite()
538{
539  owl_message *m;
540
541  /* create a message and put it on the message queue.  This simulates
542   * an incoming message */
543  m=owl_malloc(sizeof(owl_message));
544  owl_message_create_loopback(m, owl_editwin_get_text(owl_global_get_typwin(&g)));
545  owl_message_set_direction_in(m);
546  owl_global_messagequeue_addmsg(&g, m);
547
548  /* display the message as an outgoing message in the receive window */
549  if (owl_global_is_displayoutgoing(&g)) {
550    owl_function_make_outgoing_loopback(owl_editwin_get_text(owl_global_get_typwin(&g)));
551  }
552
553  /* fake a makemsg */
554  owl_function_makemsg("loopback message sent");
555
556  /* log it if we have logging turned on */
557  if (owl_global_is_logging(&g)) {
558    owl_log_outgoing_loopback(owl_editwin_get_text(owl_global_get_typwin(&g)));
559  }
560}
561
562/* If filter is non-null, looks for the next message matching
563 * that filter.  If skip_deleted, skips any deleted messages.
564 * If last_if_none, will stop at the last message in the view
565 * if no matching messages are found.  */
566void owl_function_nextmsg_full(char *filter, int skip_deleted, int last_if_none)
567{
568  int curmsg, i, viewsize, found;
569  owl_view *v;
570  owl_filter *f = NULL;
571  owl_message *m;
572
573  v=owl_global_get_current_view(&g);
574
575  if (filter) {
576    f=owl_global_get_filter(&g, filter);
577    if (!f) {
578      owl_function_error("No %s filter defined", filter);
579      return;
580    }
581  }
582
583  curmsg=owl_global_get_curmsg(&g);
584  viewsize=owl_view_get_size(v);
585  found=0;
586
587  /* just check to make sure we're in bounds... */
588  if (curmsg>viewsize-1) curmsg=viewsize-1;
589  if (curmsg<0) curmsg=0;
590
591  for (i=curmsg+1; i<viewsize; i++) {
592    m=owl_view_get_element(v, i);
593    if (skip_deleted && owl_message_is_delete(m)) continue;
594    if (f && !owl_filter_message_match(f, m)) continue;
595    found = 1;
596    break;
597  }
598
599  if (i>owl_view_get_size(v)-1) i=owl_view_get_size(v)-1;
600
601  if (!found) {
602    owl_function_makemsg("already at last%s message%s%s",
603                         skip_deleted?" non-deleted":"",
604                         filter?" in ":"", filter?filter:"");
605    /* if (!skip_deleted) owl_function_beep(); */
606  }
607
608  if (last_if_none || found) {
609    owl_global_set_curmsg(&g, i);
610    owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
611    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
612    owl_global_set_direction_downwards(&g);
613  }
614}
615
616void owl_function_prevmsg_full(char *filter, int skip_deleted, int first_if_none)
617{
618  int curmsg, i, viewsize, found;
619  owl_view *v;
620  owl_filter *f = NULL;
621  owl_message *m;
622
623  v=owl_global_get_current_view(&g);
624
625  if (filter) {
626    f=owl_global_get_filter(&g, filter);
627    if (!f) {
628      owl_function_error("No %s filter defined", filter);
629      return;
630    }
631  }
632
633  curmsg=owl_global_get_curmsg(&g);
634  viewsize=owl_view_get_size(v);
635  found=0;
636
637  /* just check to make sure we're in bounds... */
638  if (curmsg<0) curmsg=0;
639
640  for (i=curmsg-1; i>=0; i--) {
641    m=owl_view_get_element(v, i);
642    if (skip_deleted && owl_message_is_delete(m)) continue;
643    if (f && !owl_filter_message_match(f, m)) continue;
644    found = 1;
645    break;
646  }
647
648  if (i<0) i=0;
649
650  if (!found) {
651    owl_function_makemsg("already at first%s message%s%s",
652                         skip_deleted?" non-deleted":"",
653                         filter?" in ":"", filter?filter:"");
654    /* if (!skip_deleted) owl_function_beep(); */
655  }
656
657  if (first_if_none || found) {
658    owl_global_set_curmsg(&g, i);
659    owl_function_calculate_topmsg(OWL_DIRECTION_UPWARDS);
660    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
661    owl_global_set_direction_upwards(&g);
662  }
663}
664
665void owl_function_nextmsg()
666{
667  owl_function_nextmsg_full(NULL, 0, 1);
668}
669
670void owl_function_prevmsg()
671{
672  owl_function_prevmsg_full(NULL, 0, 1);
673}
674
675void owl_function_nextmsg_notdeleted()
676{
677  owl_function_nextmsg_full(NULL, 1, 1);
678}
679
680void owl_function_prevmsg_notdeleted()
681{
682  owl_function_prevmsg_full(NULL, 1, 1);
683}
684
685void owl_function_nextmsg_personal()
686{
687  owl_function_nextmsg_full("personal", 0, 0);
688}
689
690void owl_function_prevmsg_personal()
691{
692  owl_function_prevmsg_full("personal", 0, 0);
693}
694
695
696/* if move_after is 1, moves after the delete */
697void owl_function_deletecur(int move_after)
698{
699  int curmsg;
700  owl_view *v;
701
702  v=owl_global_get_current_view(&g);
703
704  /* bail if there's no current message */
705  if (owl_view_get_size(v) < 1) {
706    owl_function_error("No current message to delete");
707    return;
708  }
709
710  /* mark the message for deletion */
711  curmsg=owl_global_get_curmsg(&g);
712  owl_view_delete_element(v, curmsg);
713
714  if (move_after) {
715    /* move the poiner in the appropriate direction
716     * to the next undeleted msg */
717    if (owl_global_get_direction(&g)==OWL_DIRECTION_UPWARDS) {
718      owl_function_prevmsg_notdeleted();
719    } else {
720      owl_function_nextmsg_notdeleted();
721    }
722  }
723}
724
725void owl_function_undeletecur(int move_after)
726{
727  int curmsg;
728  owl_view *v;
729
730  v=owl_global_get_current_view(&g);
731 
732  if (owl_view_get_size(v) < 1) {
733    owl_function_error("No current message to undelete");
734    return;
735  }
736  curmsg=owl_global_get_curmsg(&g);
737
738  owl_view_undelete_element(v, curmsg);
739
740  if (move_after) {
741    if (owl_global_get_direction(&g)==OWL_DIRECTION_UPWARDS) {
742      if (curmsg>0) {
743        owl_function_prevmsg();
744      } else {
745        owl_function_nextmsg();
746      }
747    } else {
748      owl_function_nextmsg();
749    }
750  }
751
752  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
753}
754
755void owl_function_expunge()
756{
757  int curmsg;
758  owl_message *m;
759  owl_messagelist *ml;
760  owl_view *v;
761  int lastmsgid=0;
762
763  curmsg=owl_global_get_curmsg(&g);
764  v=owl_global_get_current_view(&g);
765  ml=owl_global_get_msglist(&g);
766
767  m=owl_view_get_element(v, curmsg);
768  if (m) lastmsgid = owl_message_get_id(m);
769
770  /* expunge the message list */
771  owl_messagelist_expunge(ml);
772
773  /* update all views (we only have one right now) */
774  owl_view_recalculate(v);
775
776  /* find where the new position should be
777     (as close as possible to where we last where) */
778  curmsg = owl_view_get_nearest_to_msgid(v, lastmsgid);
779  if (curmsg>owl_view_get_size(v)-1) curmsg = owl_view_get_size(v)-1;
780  if (curmsg<0) curmsg = 0;
781  owl_global_set_curmsg(&g, curmsg);
782  owl_function_calculate_topmsg(OWL_DIRECTION_NONE);
783  /* if there are no messages set the direction to down in case we
784     delete everything upwards */
785  owl_global_set_direction_downwards(&g);
786 
787  owl_function_makemsg("Messages expunged");
788  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
789}
790
791void owl_function_firstmsg()
792{
793  owl_global_set_curmsg(&g, 0);
794  owl_global_set_topmsg(&g, 0);
795  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
796  owl_global_set_direction_downwards(&g);
797}
798
799void owl_function_lastmsg_noredisplay()
800{
801  int oldcurmsg, curmsg;
802  owl_view *v;
803
804  v=owl_global_get_current_view(&g);
805  oldcurmsg=owl_global_get_curmsg(&g);
806  curmsg=owl_view_get_size(v)-1; 
807  if (curmsg<0) curmsg=0;
808  owl_global_set_curmsg(&g, curmsg);
809  if (oldcurmsg < curmsg) {
810    owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
811  } else if (curmsg<owl_view_get_size(v)) {
812    /* If already at the end, blank the screen and move curmsg
813     * past the end of the messages. */
814    owl_global_set_topmsg(&g, curmsg+1);
815    owl_global_set_curmsg(&g, curmsg+1);
816  } 
817  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
818  owl_global_set_direction_downwards(&g);
819}
820
821void owl_function_lastmsg()
822{
823  owl_function_lastmsg_noredisplay();
824  owl_mainwin_redisplay(owl_global_get_mainwin(&g)); 
825}
826
827void owl_function_shift_right()
828{
829  owl_global_set_rightshift(&g, owl_global_get_rightshift(&g)+10);
830  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
831  owl_global_set_needrefresh(&g);
832}
833
834void owl_function_shift_left()
835{
836  int shift;
837
838  shift=owl_global_get_rightshift(&g);
839  if (shift>=10) {
840    owl_global_set_rightshift(&g, shift-10);
841    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
842    owl_global_set_needrefresh(&g);
843  } else {
844    owl_function_beep();
845    owl_function_makemsg("Already full left");
846  }
847}
848
849void owl_function_unsuball()
850{
851  unsuball();
852  owl_function_makemsg("Unsubscribed from all messages.");
853}
854
855void owl_function_loadsubs(char *file)
856{
857  int ret, ret2;
858
859  ret=owl_zephyr_loadsubs(file);
860
861  /* for backwards compatibility for now */
862  ret2=owl_zephyr_loaddefaultsubs();
863
864  if (!owl_context_is_interactive(owl_global_get_context(&g))) return;
865  if (ret==0) {
866    owl_function_makemsg("Subscribed to messages from file.");
867  } else if (ret==-1) {
868    owl_function_error("Could not open file.");
869  } else {
870    owl_function_error("Error subscribing to messages from file.");
871  }
872}
873
874void owl_function_loadloginsubs(char *file)
875{
876  int ret;
877
878  ret=owl_zephyr_loadloginsubs(file);
879
880  if (!owl_context_is_interactive(owl_global_get_context(&g))) return;
881  if (ret==0) {
882    owl_function_makemsg("Subscribed to login messages from file.");
883  } else if (ret==-1) {
884    owl_function_error("Could not open file for login subscriptions.");
885  } else {
886    owl_function_error("Error subscribing to login messages from file.");
887  }
888}
889
890void owl_function_suspend()
891{
892  endwin();
893  printf("\n");
894  kill(getpid(), SIGSTOP);
895
896  /* resize to reinitialize all the windows when we come back */
897  owl_command_resize();
898}
899
900void owl_function_zaway_toggle()
901{
902  if (!owl_global_is_zaway(&g)) {
903    owl_global_set_zaway_msg(&g, owl_global_get_zaway_msg_default(&g));
904    owl_function_zaway_on();
905  } else {
906    owl_function_zaway_off();
907  }
908}
909
910void owl_function_zaway_on()
911{
912  owl_global_set_zaway_on(&g);
913  owl_function_makemsg("zaway set (%s)", owl_global_get_zaway_msg(&g));
914}
915
916void owl_function_zaway_off()
917{
918  owl_global_set_zaway_off(&g);
919  owl_function_makemsg("zaway off");
920}
921
922void owl_function_aaway_toggle()
923{
924  if (!owl_global_is_aaway(&g)) {
925    owl_global_set_aaway_msg(&g, owl_global_get_aaway_msg_default(&g));
926    owl_function_aaway_on();
927  } else {
928    owl_function_aaway_off();
929  }
930}
931
932void owl_function_aaway_on()
933{
934  owl_global_set_aaway_on(&g);
935  /* owl_aim_set_awaymsg(owl_global_get_zaway_msg(&g)); */
936  owl_function_makemsg("AIM away set (%s)", owl_global_get_aaway_msg(&g));
937}
938
939void owl_function_aaway_off()
940{
941  owl_global_set_aaway_off(&g);
942  /* owl_aim_set_awaymsg(""); */
943  owl_function_makemsg("AIM away off");
944}
945
946void owl_function_quit()
947{
948  char *ret;
949 
950  /* zlog out if we need to */
951  if (owl_global_is_shutdownlogout(&g)) {
952    owl_zephyr_zlog_out();
953  }
954
955  /* execute the commands in shutdown */
956  ret = owl_perlconfig_execute("owl::shutdown();");
957  if (ret) owl_free(ret);
958
959  /* signal our child process, if any */
960  if (owl_global_get_newmsgproc_pid(&g)) {
961    kill(owl_global_get_newmsgproc_pid(&g), SIGHUP);
962  }
963
964  /* Quit zephyr */
965  owl_zephyr_shutdown();
966
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", 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  p=popen(newbuff, "r");
2244  out=owl_malloc(1024);
2245  size=1024;
2246  strcpy(out, "");
2247  while (fgets(buff2, 1024, p)!=NULL) {
2248    size+=1024;
2249    out=owl_realloc(out, size);
2250    strcat(out, buff2);
2251  }
2252  pclose(p);
2253
2254  if (type==1) {
2255    owl_function_popless_text(out);
2256  } else if (type==0) {
2257    return out;
2258  } else if (type==2) {
2259    owl_function_adminmsg(buff, out);
2260  } else {
2261    owl_function_popless_text(out);
2262  }
2263  owl_free(out);
2264  return NULL;
2265}
2266
2267char *owl_function_perl(int argc, char **argv, char *buff, int type)
2268{
2269  /* if type == 1 display in a popup
2270   * if type == 2 display an admin messages
2271   * if type == 0 return output
2272   * else display in a popup
2273   */
2274  char *perlout;
2275
2276  if (argc<2) {
2277    owl_function_error("Wrong number of arguments to perl command");
2278    return NULL;
2279  }
2280
2281  /* consume first token (argv[0]) */
2282  buff = skiptokens(buff, 1);
2283
2284  perlout = owl_perlconfig_execute(buff);
2285  if (perlout) { 
2286    if (type==1) {
2287      owl_function_popless_text(perlout);
2288    } else if (type==2) {
2289      owl_function_adminmsg(buff, perlout);
2290    } else if (type==0) {
2291      return perlout;
2292    } else {
2293      owl_function_popless_text(perlout);
2294    }
2295    owl_free(perlout);
2296  }
2297  return NULL;
2298}
2299
2300void owl_function_change_currentview_filter(char *filtname)
2301{
2302  owl_view *v;
2303  owl_filter *f;
2304  int curid=-1, newpos, curmsg;
2305  owl_message *curm=NULL;
2306
2307  v=owl_global_get_current_view(&g);
2308
2309  curmsg=owl_global_get_curmsg(&g);
2310  if (curmsg==-1) {
2311    owl_function_debugmsg("Hit the curmsg==-1 case in change_view");
2312  } else {
2313    curm=owl_view_get_element(v, curmsg);
2314    if (curm) {
2315      curid=owl_message_get_id(curm);
2316      owl_view_save_curmsgid(v, curid);
2317    }
2318  }
2319
2320  f=owl_global_get_filter(&g, filtname);
2321  if (!f) {
2322    owl_function_error("Unknown filter %s", filtname);
2323    return;
2324  }
2325
2326  owl_view_new_filter(v, f);
2327
2328  /* Figure out what to set the current message to.
2329   * - If the view we're leaving has messages in it, go to the closest message
2330   *   to the last message pointed to in that view.
2331   * - If the view we're leaving is empty, try to restore the position
2332   *   from the last time we were in the new view.  */
2333  if (curm) {
2334    newpos = owl_view_get_nearest_to_msgid(v, curid);
2335  } else {
2336    newpos = owl_view_get_nearest_to_saved(v);
2337  }
2338
2339  owl_global_set_curmsg(&g, newpos);
2340  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
2341  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2342  owl_global_set_direction_downwards(&g);
2343}
2344
2345void owl_function_create_filter(int argc, char **argv)
2346{
2347  owl_filter *f;
2348  owl_view *v;
2349  int ret, inuse=0;
2350
2351  if (argc < 2) {
2352    owl_function_error("Wrong number of arguments to filter command");
2353    return;
2354  }
2355
2356  owl_function_debugmsg("owl_function_create_filter: starting to create filter named %s", argv[1]);
2357
2358  v=owl_global_get_current_view(&g);
2359
2360  /* don't touch the all filter */
2361  if (!strcmp(argv[1], "all")) {
2362    owl_function_error("You may not change the 'all' filter.");
2363    return;
2364  }
2365
2366  /* deal with the case of trying change the filter color */
2367  if (argc==4 && !strcmp(argv[2], "-c")) {
2368    f=owl_global_get_filter(&g, argv[1]);
2369    if (!f) {
2370      owl_function_error("The filter '%s' does not exist.", argv[1]);
2371      return;
2372    }
2373    if (owl_util_string_to_color(argv[3])==-1) {
2374      owl_function_error("The color '%s' is not available.", argv[3]);
2375      return;
2376    }
2377    owl_filter_set_color(f, owl_util_string_to_color(argv[3]));
2378    owl_global_set_needrefresh(&g);
2379    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2380    return;
2381  }
2382
2383  /* create the filter and check for errors */
2384  f=owl_malloc(sizeof(owl_filter));
2385  ret=owl_filter_init(f, argv[1], argc-2, argv+2);
2386  if (ret==-1) {
2387    owl_free(f);
2388    owl_function_error("Invalid filter");
2389    return;
2390  }
2391
2392  /* if the named filter is in use by the current view, remember it */
2393  if (!strcmp(owl_view_get_filtname(v), argv[1])) {
2394    inuse=1;
2395  }
2396
2397  /* if the named filter already exists, nuke it */
2398  if (owl_global_get_filter(&g, argv[1])) {
2399    owl_global_remove_filter(&g, argv[1]);
2400  }
2401
2402  /* add the filter */
2403  owl_global_add_filter(&g, f);
2404
2405  /* if it was in use by the current view then update */
2406  if (inuse) {
2407    owl_function_change_currentview_filter(argv[1]);
2408  }
2409  owl_global_set_needrefresh(&g);
2410  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2411}
2412
2413/* If 'filtername' does not start with 'not-' create a filter named
2414 * 'not-<filtername>' defined as "not filter <filtername>".  If the
2415 * filter 'not-<filtername>' already exists, do not overwrite it.  If
2416 * 'filtername' begins with 'not-' and a filter 'filtername' already
2417 * exists, then do nothing.  If the filter 'filtername' does not
2418 * exist, create it and define it as 'not filter <filtername>'
2419 *
2420 * Returns the name of the negated filter, which the caller must free.
2421 */
2422char *owl_function_create_negative_filter(char *filtername)
2423{
2424  char *newname;
2425  owl_filter *tmpfilt;
2426  char *argv[5];
2427
2428  owl_function_debugmsg("owl_function_create_negative_filter");
2429 
2430  if (!strncmp(filtername, "not-", 4)) {
2431    newname=owl_strdup(filtername+4);
2432  } else {
2433    newname=owl_sprintf("not-%s", filtername);
2434  }
2435
2436  tmpfilt=owl_global_get_filter(&g, newname);
2437  if (!tmpfilt) {
2438    argv[0]="filter"; /* anything is fine here */
2439    argv[1]=newname;
2440    argv[2]="not";
2441    argv[3]="filter";
2442    argv[4]=filtername;
2443    owl_function_create_filter(5, argv);
2444  }
2445
2446  owl_function_debugmsg("owl_function_create_negative_filter: returning with %s", newname);
2447  return(newname);
2448}
2449
2450void owl_function_show_filters()
2451{
2452  owl_list *l;
2453  owl_filter *f;
2454  int i, j;
2455  owl_fmtext fm;
2456
2457  owl_fmtext_init_null(&fm);
2458
2459  l=owl_global_get_filterlist(&g);
2460  j=owl_list_get_size(l);
2461
2462  owl_fmtext_append_bold(&fm, "Filters:\n");
2463
2464  for (i=0; i<j; i++) {
2465    f=owl_list_get_element(l, i);
2466    owl_fmtext_append_normal(&fm, "   ");
2467    if (owl_global_get_hascolors(&g)) {
2468      owl_fmtext_append_normal_color(&fm, owl_filter_get_name(f), owl_filter_get_color(f));
2469    } else {
2470      owl_fmtext_append_normal(&fm, owl_filter_get_name(f));
2471    }
2472    owl_fmtext_append_normal(&fm, "\n");
2473  }
2474  owl_function_popless_fmtext(&fm);
2475  owl_fmtext_free(&fm);
2476}
2477
2478void owl_function_show_filter(char *name)
2479{
2480  owl_filter *f;
2481  char buff[5000];
2482
2483  f=owl_global_get_filter(&g, name);
2484  if (!f) {
2485    owl_function_error("There is no filter named %s", name);
2486    return;
2487  }
2488  owl_filter_print(f, buff);
2489  owl_function_popless_text(buff);
2490}
2491
2492void owl_function_show_zpunts()
2493{
2494  owl_filter *f;
2495  owl_list *fl;
2496  char buff[5000];
2497  owl_fmtext fm;
2498  int i, j;
2499
2500  owl_fmtext_init_null(&fm);
2501
2502  fl=owl_global_get_puntlist(&g);
2503  j=owl_list_get_size(fl);
2504  owl_fmtext_append_bold(&fm, "Active zpunt filters:\n");
2505
2506  for (i=0; i<j; i++) {
2507    f=owl_list_get_element(fl, i);
2508    owl_filter_print(f, buff);
2509    owl_fmtext_append_normal(&fm, buff);
2510  }
2511  owl_function_popless_fmtext(&fm);
2512  owl_fmtext_free(&fm);
2513}
2514
2515/* Create a filter for a class, instance if one doesn't exist.  If
2516 * instance is NULL then catch all messgaes in the class.  Returns the
2517 * name of the filter, which the caller must free.
2518 */
2519char *owl_function_classinstfilt(char *class, char *instance) 
2520{
2521  owl_list *fl;
2522  owl_filter *f;
2523  char *argbuff, *filtname;
2524  char *tmpclass, *tmpinstance = NULL;
2525  int len;
2526
2527  fl=owl_global_get_filterlist(&g);
2528
2529  /* name for the filter */
2530  len=strlen(class)+30;
2531  if (instance) len+=strlen(instance);
2532  filtname=owl_malloc(len);
2533  if (!instance) {
2534    sprintf(filtname, "class-%s", class);
2535  } else {
2536    sprintf(filtname, "class-%s-instance-%s", class, instance);
2537  }
2538  /* downcase it */
2539  downstr(filtname);
2540  /* turn spaces into dots */
2541  owl_text_tr(filtname, ' ', '.');
2542 
2543  /* if it already exists then go with it.  This lets users override */
2544  if (owl_global_get_filter(&g, filtname)) {
2545    return(filtname);
2546  }
2547
2548  /* create the new filter */
2549  argbuff=owl_malloc(len+20);
2550  tmpclass=owl_text_quote(class, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2551  owl_text_tr(tmpclass, ' ', '.');
2552  if (instance) {
2553    tmpinstance=owl_text_quote(instance, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2554    owl_text_tr(tmpinstance, ' ', '.');
2555  }
2556  sprintf(argbuff, "( class ^%s$ )", tmpclass);
2557  if (tmpinstance) {
2558    sprintf(argbuff, "%s and ( instance ^%s$ )", argbuff, tmpinstance);
2559  }
2560  owl_free(tmpclass);
2561  if (tmpinstance) owl_free(tmpinstance);
2562
2563  f=owl_malloc(sizeof(owl_filter));
2564  owl_filter_init_fromstring(f, filtname, argbuff);
2565
2566  /* add it to the global list */
2567  owl_global_add_filter(&g, f);
2568
2569  owl_free(argbuff);
2570  return(filtname);
2571}
2572
2573/* Create a filter for personal zephyrs to or from the specified
2574 * zephyr user.  Includes login/logout notifications for the user.
2575 * The name of the filter will be 'user-<user>'.  If a filter already
2576 * exists with this name, no new filter will be created.  This allows
2577 * the configuration to override this function.  Returns the name of
2578 * the filter, which the caller must free.
2579 */
2580char *owl_function_zuserfilt(char *user)
2581{
2582  owl_filter *f;
2583  char *argbuff, *longuser, *shortuser, *filtname;
2584
2585  /* stick the local realm on if it's not there */
2586  longuser=long_zuser(user);
2587  shortuser=short_zuser(user);
2588
2589  /* name for the filter */
2590  filtname=owl_malloc(strlen(shortuser)+20);
2591  sprintf(filtname, "user-%s", shortuser);
2592
2593  /* if it already exists then go with it.  This lets users override */
2594  if (owl_global_get_filter(&g, filtname)) {
2595    return(owl_strdup(filtname));
2596  }
2597
2598  /* create the new-internal filter */
2599  f=owl_malloc(sizeof(owl_filter));
2600
2601  argbuff=owl_malloc(strlen(longuser)+1000);
2602  sprintf(argbuff, "( type ^zephyr$ and ( class ^message$ and instance ^personal$ and ");
2603  sprintf(argbuff, "%s ( ( direction ^in$ and sender ^%s$ ) or ( direction ^out$ and recipient ^%s$ ) ) )", argbuff, longuser, longuser);
2604  sprintf(argbuff, "%s or ( ( class ^login$ ) and ( sender ^%s$ ) ) )", argbuff, longuser);
2605
2606  owl_filter_init_fromstring(f, filtname, argbuff);
2607
2608  /* add it to the global list */
2609  owl_global_add_filter(&g, f);
2610
2611  /* free stuff */
2612  owl_free(argbuff);
2613  owl_free(longuser);
2614  owl_free(shortuser);
2615
2616  return(filtname);
2617}
2618
2619/* Create a filter for AIM IM messages to or from the specified
2620 * screenname.  The name of the filter will be 'aimuser-<user>'.  If a
2621 * filter already exists with this name, no new filter will be
2622 * created.  This allows the configuration to override this function.
2623 * Returns the name of the filter, which the caller must free.
2624 */
2625char *owl_function_aimuserfilt(char *user)
2626{
2627  owl_filter *f;
2628  char *argbuff, *filtname;
2629
2630  /* name for the filter */
2631  filtname=owl_malloc(strlen(user)+40);
2632  sprintf(filtname, "aimuser-%s", user);
2633
2634  /* if it already exists then go with it.  This lets users override */
2635  if (owl_global_get_filter(&g, filtname)) {
2636    return(owl_strdup(filtname));
2637  }
2638
2639  /* create the new-internal filter */
2640  f=owl_malloc(sizeof(owl_filter));
2641
2642  argbuff=owl_malloc(1000);
2643  sprintf(argbuff,
2644          "( type ^aim$ and ( ( sender ^%s$ and recipient ^%s$ ) or ( sender ^%s$ and recipient ^%s$ ) ) )",
2645          user, owl_global_get_aim_screenname(&g), owl_global_get_aim_screenname(&g), user);
2646
2647  owl_filter_init_fromstring(f, filtname, argbuff);
2648
2649  /* add it to the global list */
2650  owl_global_add_filter(&g, f);
2651
2652  /* free stuff */
2653  owl_free(argbuff);
2654
2655  return(filtname);
2656}
2657
2658char *owl_function_typefilt(char *type)
2659{
2660  owl_filter *f;
2661  char *argbuff, *filtname;
2662
2663  /* name for the filter */
2664  filtname=owl_sprintf("type-%s", type);
2665
2666  /* if it already exists then go with it.  This lets users override */
2667  if (owl_global_get_filter(&g, filtname)) {
2668    return filtname;
2669  }
2670
2671  /* create the new-internal filter */
2672  f=owl_malloc(sizeof(owl_filter));
2673
2674  argbuff = owl_sprintf("type ^%s$", type);
2675
2676  owl_filter_init_fromstring(f, filtname, argbuff);
2677
2678  /* add it to the global list */
2679  owl_global_add_filter(&g, f);
2680
2681  /* free stuff */
2682  owl_free(argbuff);
2683
2684  return filtname;
2685}
2686
2687/* If flag is 1, marks for deletion.  If flag is 0,
2688 * unmarks for deletion. */
2689void owl_function_delete_curview_msgs(int flag)
2690{
2691  owl_view *v;
2692  int i, j;
2693
2694  v=owl_global_get_current_view(&g);
2695  j=owl_view_get_size(v);
2696  for (i=0; i<j; i++) {
2697    if (flag == 1) {
2698      owl_message_mark_delete(owl_view_get_element(v, i));
2699    } else if (flag == 0) {
2700      owl_message_unmark_delete(owl_view_get_element(v, i));
2701    }
2702  }
2703
2704  owl_function_makemsg("%i messages marked for %sdeletion", j, flag?"":"un");
2705
2706  owl_mainwin_redisplay(owl_global_get_mainwin(&g)); 
2707}
2708
2709/* Create a filter based on the current message.  Returns the name of
2710 * a filter or null.  The caller must free this name.
2711 *
2712 * if the curmsg is a personal zephyr return a filter name
2713 *    to the zephyr converstaion with that user.
2714 * If the curmsg is a zephyr class message, instance foo, recip *,
2715 *    return a filter name to the class, inst.
2716 * If the curmsg is a zephyr class message and type==0 then
2717 *    return a filter name for just the class.
2718 * If the curmsg is a zephyr class message and type==1 then
2719 *    return a filter name for the class and instance.
2720 * If the curmsg is a personal AIM message returna  filter
2721 *    name to the AIM conversation with that user
2722 */
2723char *owl_function_smartfilter(int type)
2724{
2725  owl_view *v;
2726  owl_message *m;
2727  char *zperson, *filtname=NULL;
2728 
2729  v=owl_global_get_current_view(&g);
2730  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2731
2732  if (!m || owl_view_get_size(v)==0) {
2733    owl_function_error("No message selected\n");
2734    return(NULL);
2735  }
2736
2737  /* very simple handling of admin messages for now */
2738  if (owl_message_is_type_admin(m)) {
2739    return(owl_function_typefilt("admin"));
2740  }
2741
2742  /* very simple handling of loopback messages for now */
2743  if (owl_message_is_type_loopback(m)) {
2744    return(owl_function_typefilt("loopback"));
2745  }
2746
2747  /* aim messages */
2748  if (owl_message_is_type_aim(m)) {
2749    if (owl_message_is_direction_in(m)) {
2750      filtname=owl_function_aimuserfilt(owl_message_get_sender(m));
2751    } else if (owl_message_is_direction_out(m)) {
2752      filtname=owl_function_aimuserfilt(owl_message_get_recipient(m));
2753    }
2754    return(filtname);
2755  }
2756
2757  /* narrow personal and login messages to the sender or recip as appropriate */
2758  if (owl_message_is_personal(m) || owl_message_is_loginout(m)) {
2759    if (owl_message_is_type_zephyr(m)) {
2760      if (owl_message_is_direction_in(m)) {
2761        zperson=short_zuser(owl_message_get_sender(m));
2762      } else {
2763        zperson=short_zuser(owl_message_get_recipient(m));
2764      }
2765      filtname=owl_function_zuserfilt(zperson);
2766      owl_free(zperson);
2767      return(filtname);
2768    }
2769    return(NULL);
2770  }
2771
2772  /* narrow class MESSAGE, instance foo, recip * messages to class, inst */
2773  if (!strcasecmp(owl_message_get_class(m), "message") && !owl_message_is_personal(m)) {
2774    filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2775    return(filtname);
2776  }
2777
2778  /* otherwise narrow to the class */
2779  if (type==0) {
2780    filtname=owl_function_classinstfilt(owl_message_get_class(m), NULL);
2781  } else if (type==1) {
2782    filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2783  }
2784  return(filtname);
2785}
2786
2787void owl_function_smartzpunt(int type)
2788{
2789  /* Starts a zpunt command based on the current class,instance pair.
2790   * If type=0, uses just class.  If type=1, uses instance as well. */
2791  owl_view *v;
2792  owl_message *m;
2793  char *cmd, *cmdprefix, *mclass, *minst;
2794 
2795  v=owl_global_get_current_view(&g);
2796  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2797
2798  if (!m || owl_view_get_size(v)==0) {
2799    owl_function_error("No message selected\n");
2800    return;
2801  }
2802
2803  /* for now we skip admin messages. */
2804  if (owl_message_is_type_admin(m)
2805      || owl_message_is_loginout(m)
2806      || !owl_message_is_type_zephyr(m)) {
2807    owl_function_error("smartzpunt doesn't support this message type.");
2808    return;
2809  }
2810
2811  mclass = owl_message_get_class(m);
2812  minst = owl_message_get_instance(m);
2813  if (!mclass || !*mclass || *mclass==' '
2814      || (!strcasecmp(mclass, "message") && !strcasecmp(minst, "personal"))
2815      || (type && (!minst || !*minst|| *minst==' '))) {
2816    owl_function_error("smartzpunt can't safely do this for <%s,%s>",
2817                         mclass, minst);
2818  } else {
2819    cmdprefix = "start-command zpunt ";
2820    cmd = owl_malloc(strlen(cmdprefix)+strlen(mclass)+strlen(minst)+10);
2821    strcpy(cmd, cmdprefix);
2822    strcat(cmd, owl_getquoting(mclass));
2823    strcat(cmd, mclass);
2824    strcat(cmd, owl_getquoting(mclass));
2825    if (type) {
2826      strcat(cmd, " ");
2827      strcat(cmd, owl_getquoting(minst));
2828      strcat(cmd, minst);
2829      strcat(cmd, owl_getquoting(minst));
2830    } else {
2831      strcat(cmd, " *");
2832    }
2833    owl_function_command(cmd);
2834    owl_free(cmd);
2835  }
2836}
2837
2838void owl_function_color_current_filter(char *color)
2839{
2840  owl_filter *f;
2841  char *name;
2842
2843  name=owl_view_get_filtname(owl_global_get_current_view(&g));
2844  f=owl_global_get_filter(&g, name);
2845  if (!f) {
2846    owl_function_error("Unknown filter");
2847    return;
2848  }
2849
2850  /* don't touch the all filter */
2851  if (!strcmp(name, "all")) {
2852    owl_function_error("You may not change the 'all' filter.");
2853    return;
2854  }
2855
2856  /* deal with the case of trying change the filter color */
2857  if (owl_util_string_to_color(color)==-1) {
2858    owl_function_error("No color named '%s' avilable.");
2859    return;
2860  }
2861  owl_filter_set_color(f, owl_util_string_to_color(color));
2862  owl_global_set_needrefresh(&g);
2863  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2864}
2865
2866void owl_function_show_colors()
2867{
2868  owl_fmtext fm;
2869
2870  owl_fmtext_init_null(&fm);
2871  owl_fmtext_append_normal_color(&fm, "default\n", OWL_COLOR_DEFAULT);
2872  owl_fmtext_append_normal_color(&fm, "red\n", OWL_COLOR_RED);
2873  owl_fmtext_append_normal_color(&fm, "green\n", OWL_COLOR_GREEN);
2874  owl_fmtext_append_normal_color(&fm, "yellow\n", OWL_COLOR_YELLOW);
2875  owl_fmtext_append_normal_color(&fm, "blue\n", OWL_COLOR_BLUE);
2876  owl_fmtext_append_normal_color(&fm, "magenta\n", OWL_COLOR_MAGENTA);
2877  owl_fmtext_append_normal_color(&fm, "cyan\n", OWL_COLOR_CYAN);
2878  owl_fmtext_append_normal_color(&fm, "white\n", OWL_COLOR_WHITE);
2879
2880  owl_function_popless_fmtext(&fm);
2881  owl_fmtext_free(&fm);
2882}
2883
2884/* add the given class, inst, recip to the punt list for filtering.
2885 *   if direction==0 then punt
2886 *   if direction==1 then unpunt
2887 */
2888void owl_function_zpunt(char *class, char *inst, char *recip, int direction)
2889{
2890  owl_filter *f;
2891  owl_list *fl;
2892  char *buff;
2893  char *quoted;
2894  int ret, i, j;
2895
2896  fl=owl_global_get_puntlist(&g);
2897
2898  /* first, create the filter */
2899  f=malloc(sizeof(owl_filter));
2900  buff=malloc(strlen(class)+strlen(inst)+strlen(recip)+100);
2901  strcpy(buff, "class");
2902  if (!strcmp(class, "*")) {
2903    strcat(buff, " .*");
2904  } else {
2905    quoted=owl_text_quote(class, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2906    owl_text_tr(quoted, ' ', '.');
2907    sprintf(buff, "%s ^%s$", buff, quoted);
2908    owl_free(quoted);
2909  }
2910  if (!strcmp(inst, "*")) {
2911    strcat(buff, " and instance .*");
2912  } else {
2913    quoted=owl_text_quote(inst, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2914    owl_text_tr(quoted, ' ', '.');
2915    sprintf(buff, "%s and instance ^%s$", buff, quoted);
2916    owl_free(quoted);
2917  }
2918  if (strcmp(recip, "*")) {
2919    quoted=owl_text_quote(recip, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2920    owl_text_tr(quoted, ' ', '.');
2921    sprintf(buff, "%s and recipient ^%s$", buff, quoted);
2922    owl_free(quoted);
2923  }
2924 
2925  owl_function_debugmsg("About to filter %s", buff);
2926  ret=owl_filter_init_fromstring(f, "punt-filter", buff);
2927  owl_free(buff);
2928  if (ret) {
2929    owl_function_error("Error creating filter for zpunt");
2930    owl_filter_free(f);
2931    return;
2932  }
2933
2934  /* Check for an identical filter */
2935  j=owl_list_get_size(fl);
2936  for (i=0; i<j; i++) {
2937    if (owl_filter_equiv(f, owl_list_get_element(fl, i))) {
2938      /* if we're punting, then just silently bow out on this duplicate */
2939      if (direction==0) {
2940        owl_filter_free(f);
2941        return;
2942      }
2943
2944      /* if we're unpunting, then remove this filter from the puntlist */
2945      if (direction==1) {
2946        owl_filter_free(owl_list_get_element(fl, i));
2947        owl_list_remove_element(fl, i);
2948        return;
2949      }
2950    }
2951  }
2952
2953  /* If we're punting, add the filter to the global punt list */
2954  if (direction==0) {
2955    owl_list_append_element(fl, f);
2956  }
2957}
2958
2959void owl_function_activate_keymap(char *keymap)
2960{
2961  if (!owl_keyhandler_activate(owl_global_get_keyhandler(&g), keymap)) {
2962    owl_function_error("Unable to activate keymap '%s'", keymap);
2963  }
2964}
2965
2966void owl_function_show_keymaps()
2967{
2968  owl_list l;
2969  owl_fmtext fm;
2970  owl_keymap *km;
2971  owl_keyhandler *kh;
2972  int i, numkm;
2973  char *kmname;
2974
2975  kh = owl_global_get_keyhandler(&g);
2976  owl_fmtext_init_null(&fm);
2977  owl_fmtext_append_bold(&fm, "Keymaps:   ");
2978  owl_fmtext_append_normal(&fm, "(use 'show keymap <name>' for details)\n");
2979  owl_keyhandler_get_keymap_names(kh, &l);
2980  owl_fmtext_append_list(&fm, &l, "\n", owl_function_keymap_summary);
2981  owl_fmtext_append_normal(&fm, "\n");
2982
2983  numkm = owl_list_get_size(&l);
2984  for (i=0; i<numkm; i++) {
2985    kmname = owl_list_get_element(&l, i);
2986    km = owl_keyhandler_get_keymap(kh, kmname);
2987    owl_fmtext_append_bold(&fm, "\n\n----------------------------------------------------------------------------------------------------\n\n");
2988    owl_keymap_get_details(km, &fm);   
2989  }
2990  owl_fmtext_append_normal(&fm, "\n");
2991 
2992  owl_function_popless_fmtext(&fm);
2993  owl_keyhandler_keymap_namelist_free(&l);
2994  owl_fmtext_free(&fm);
2995}
2996
2997char *owl_function_keymap_summary(void *name)
2998{
2999  owl_keymap *km
3000    = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
3001  if (km) return owl_keymap_summary(km);
3002  else return(NULL);
3003}
3004
3005/* TODO: implement for real */
3006void owl_function_show_keymap(char *name)
3007{
3008  owl_fmtext fm;
3009  owl_keymap *km;
3010
3011  owl_fmtext_init_null(&fm);
3012  km = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
3013  if (km) {
3014    owl_keymap_get_details(km, &fm);
3015  } else {
3016    owl_fmtext_append_normal(&fm, "No such keymap...\n");
3017  } 
3018  owl_function_popless_fmtext(&fm);
3019  owl_fmtext_free(&fm);
3020}
3021
3022void owl_function_help_for_command(char *cmdname)
3023{
3024  owl_fmtext fm;
3025
3026  owl_fmtext_init_null(&fm);
3027  owl_cmd_get_help(owl_global_get_cmddict(&g), cmdname, &fm);
3028  owl_function_popless_fmtext(&fm); 
3029  owl_fmtext_free(&fm);
3030}
3031
3032void owl_function_search_start(char *string, int direction)
3033{
3034  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
3035  owl_global_set_search_active(&g, string);
3036  owl_function_search_helper(0, direction);
3037}
3038
3039void owl_function_search_continue(int direction)
3040{
3041  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
3042  owl_function_search_helper(1, direction);
3043}
3044
3045void owl_function_search_helper(int mode, int direction)
3046{
3047  /* move to a message that contains the string.  If direction is
3048   * OWL_DIRECTION_DOWNWARDS then search fowards, if direction is
3049   * OWL_DIRECTION_UPWARDS then search backwards.
3050   *
3051   * If mode==0 then it will stay on the current message if it
3052   * contains the string.
3053   */
3054
3055  owl_view *v;
3056  int viewsize, i, curmsg, start;
3057  owl_message *m;
3058
3059  v=owl_global_get_current_view(&g);
3060  viewsize=owl_view_get_size(v);
3061  curmsg=owl_global_get_curmsg(&g);
3062 
3063  if (viewsize==0) {
3064    owl_function_error("No messages present");
3065    return;
3066  }
3067
3068  if (mode==0) {
3069    start=curmsg;
3070  } else if (direction==OWL_DIRECTION_DOWNWARDS) {
3071    start=curmsg+1;
3072  } else {
3073    start=curmsg-1;
3074  }
3075
3076  /* bounds check */
3077  if (start>=viewsize || start<0) {
3078    owl_function_error("No further matches found");
3079    return;
3080  }
3081
3082  for (i=start; i<viewsize && i>=0;) {
3083    m=owl_view_get_element(v, i);
3084    if (owl_message_search(m, owl_global_get_search_string(&g))) {
3085      owl_global_set_curmsg(&g, i);
3086      owl_function_calculate_topmsg(direction);
3087      owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3088      if (direction==OWL_DIRECTION_DOWNWARDS) {
3089        owl_global_set_direction_downwards(&g);
3090      } else {
3091        owl_global_set_direction_upwards(&g);
3092      }
3093      return;
3094    }
3095    if (direction==OWL_DIRECTION_DOWNWARDS) {
3096      i++;
3097    } else {
3098      i--;
3099    }
3100  }
3101  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3102  owl_function_error("No matches found");
3103}
3104
3105/* strips formatting from ztext and returns the unformatted text.
3106 * caller is responsible for freeing. */
3107char *owl_function_ztext_stylestrip(char *zt)
3108{
3109  owl_fmtext fm;
3110  char *plaintext;
3111
3112  owl_fmtext_init_null(&fm);
3113  owl_fmtext_append_ztext(&fm, zt);
3114  plaintext = owl_fmtext_print_plain(&fm);
3115  owl_fmtext_free(&fm);
3116  return(plaintext);
3117}
3118
3119/* Popup a buddylisting.  If filename is NULL use the default .anyone */
3120void owl_function_buddylist(int aim, int zephyr, char *filename)
3121{
3122  int i, j, x, idle;
3123  owl_fmtext fm;
3124  owl_buddylist *bl;
3125  owl_buddy *b;
3126  owl_list anyone;
3127  char *foo, *timestr;
3128#ifdef HAVE_LIBZEPHYR
3129  char *tmp, *user, *line;
3130  ZLocations_t location[200];
3131  int numlocs, ret;
3132#endif
3133
3134  owl_fmtext_init_null(&fm);
3135
3136  /* AIM first */
3137  if (aim && owl_global_is_aimloggedin(&g)) {
3138    bl=owl_global_get_buddylist(&g);
3139
3140    owl_fmtext_append_bold(&fm, "AIM users logged in:\n");
3141    /* we're assuming AIM for now */
3142    j=owl_buddylist_get_size(bl);
3143    for (i=0; i<j; i++) {
3144      b=owl_buddylist_get_buddy_n(bl, i);
3145      idle=owl_buddy_get_idle_time(b);
3146      if (idle!=0) {
3147        timestr=owl_util_minutes_to_timestr(idle);
3148      } else {
3149        timestr=owl_strdup("");
3150      }
3151      foo=owl_sprintf("  %-20.20s %-12.12s\n", owl_buddy_get_name(b), timestr);
3152      owl_fmtext_append_normal(&fm, foo);
3153      owl_free(timestr);
3154      owl_free(foo);
3155    }
3156  }
3157
3158#ifdef HAVE_LIBZEPHYR
3159  if (zephyr) {
3160    owl_fmtext_append_bold(&fm, "Zephyr users logged in:\n");
3161    owl_list_create(&anyone);
3162    ret=owl_zephyr_get_anyone_list(&anyone, filename);
3163    if (ret) {
3164      owl_fmtext_append_normal(&fm, "  Error opening file for zephyr buddies.\n");
3165    } else {
3166      j=owl_list_get_size(&anyone);
3167      for (i=0; i<j; i++) {
3168        user=owl_list_get_element(&anyone, i);
3169        ret=ZLocateUser(user, &numlocs, ZAUTH);
3170        if (ret!=ZERR_NONE) {
3171          owl_function_error("Error getting location for %s", user);
3172          continue;
3173        }
3174       
3175        numlocs=200;
3176        ret=ZGetLocations(location, &numlocs);
3177        if (ret==0) {
3178          for (x=0; x<numlocs; x++) {
3179            line=malloc(strlen(location[x].host)+strlen(location[x].time)+strlen(location[x].tty)+100);
3180            tmp=short_zuser(user);
3181            sprintf(line, "  %-10.10s %-24.24s %-12.12s  %20.20s\n",
3182                    tmp,
3183                    location[x].host,
3184                    location[x].tty,
3185                    location[x].time);
3186            owl_fmtext_append_normal(&fm, line);
3187            owl_free(tmp);
3188          }
3189          if (numlocs>=200) {
3190            owl_fmtext_append_normal(&fm, "  Too many locations found for this user, truncating.\n");
3191          }
3192        }
3193      }
3194    }
3195    owl_list_free_all(&anyone, owl_free);
3196  }
3197#endif
3198 
3199  owl_function_popless_fmtext(&fm);
3200  owl_fmtext_free(&fm);
3201}
3202
3203/* Dump messages in the current view to the file 'filename'. */
3204void owl_function_dump(char *filename) 
3205{
3206  int i, j, count;
3207  owl_message *m;
3208  owl_view *v;
3209  FILE *file;
3210
3211  v=owl_global_get_current_view(&g);
3212
3213  /* in the future make it ask yes/no */
3214  /*
3215  ret=stat(filename, &sbuf);
3216  if (!ret) {
3217    ret=owl_function_askyesno("File exists, continue? [Y/n]");
3218    if (!ret) return;
3219  }
3220  */
3221
3222  file=fopen(filename, "w");
3223  if (!file) {
3224    owl_function_error("Error opening file");
3225    return;
3226  }
3227
3228  count=0;
3229  j=owl_view_get_size(v);
3230  for (i=0; i<j; i++) {
3231    m=owl_view_get_element(v, i);
3232    fputs(owl_message_get_text(m), file);
3233  }
3234  fclose(file);
3235  owl_function_makemsg("Messages dumped to %s", filename);
3236}
3237
3238void owl_function_do_newmsgproc(void)
3239{
3240  if (owl_global_get_newmsgproc(&g) && strcmp(owl_global_get_newmsgproc(&g), "")) {
3241    /* if there's a process out there, we need to check on it */
3242    if (owl_global_get_newmsgproc_pid(&g)) {
3243      owl_function_debugmsg("Checking on newmsgproc pid==%i", owl_global_get_newmsgproc_pid(&g));
3244      owl_function_debugmsg("Waitpid return is %i", waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG));
3245      waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG);
3246      if (waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG)==-1) {
3247        /* it exited */
3248        owl_global_set_newmsgproc_pid(&g, 0);
3249        owl_function_debugmsg("newmsgproc exited");
3250      } else {
3251        owl_function_debugmsg("newmsgproc did not exit");
3252      }
3253    }
3254   
3255    /* if it exited, fork & exec a new one */
3256    if (owl_global_get_newmsgproc_pid(&g)==0) {
3257      int i, myargc;
3258      i=fork();
3259      if (i) {
3260        /* parent set the child's pid */
3261        owl_global_set_newmsgproc_pid(&g, i);
3262        owl_function_debugmsg("I'm the parent and I started a new newmsgproc with pid %i", i);
3263      } else {
3264        /* child exec's the program */
3265        char **parsed;
3266        parsed=owl_parseline(owl_global_get_newmsgproc(&g), &myargc);
3267        if (myargc < 0) {
3268          owl_function_debugmsg("Could not parse newmsgproc '%s': unbalanced quotes?", owl_global_get_newmsgproc(&g));
3269        }
3270        if (myargc <= 0) {
3271          _exit(127);
3272        }
3273        parsed=realloc(parsed, sizeof(*parsed) * (myargc+1));
3274        parsed[myargc] = NULL;
3275       
3276        owl_function_debugmsg("About to exec \"%s\" with %d arguments", parsed[0], myargc);
3277       
3278        execvp(parsed[0], parsed);
3279       
3280       
3281        /* was there an error exec'ing? */
3282        owl_function_debugmsg("Cannot run newmsgproc '%s': cannot exec '%s': %s", 
3283                              owl_global_get_newmsgproc(&g), parsed[0], strerror(errno));
3284        _exit(127);
3285      }
3286    }
3287  }
3288}
3289
3290/* print the xterm escape sequence to raise the window */
3291void owl_function_xterm_raise(void)
3292{
3293  printf("\033[5t");
3294}
3295
3296/* print the xterm escape sequence to deiconify the window */
3297void owl_function_xterm_deiconify(void)
3298{
3299  printf("\033[1t");
3300}
3301
3302/* Add the specified command to the startup file.  Eventually this
3303 * should be clever, and rewriting settings that will obviosly
3304 * override earlier settings with 'set' 'bindkey' and 'alias'
3305 * commands.  For now though we just remove any line that would
3306 * duplicate this one and then append this line to the end of
3307 * startupfile.
3308 */
3309void owl_function_addstartup(char *buff)
3310{
3311  FILE *file;
3312  char *filename;
3313
3314  filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
3315  file=fopen(filename, "a");
3316  if (!file) {
3317    owl_function_error("Error opening startupfile for new command");
3318    owl_free(filename);
3319    return;
3320  }
3321
3322  /* delete earlier copies */
3323  owl_util_file_deleteline(filename, buff, 1);
3324  owl_free(filename);
3325
3326  /* add this line */
3327  fprintf(file, "%s\n", buff);
3328
3329  fclose(file);
3330}
3331
3332/* Remove the specified command from the startup file. */
3333void owl_function_delstartup(char *buff)
3334{
3335  char *filename;
3336  filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
3337  owl_util_file_deleteline(filename, buff, 1);
3338  owl_free(filename);
3339}
3340
3341/* Execute owl commands from the given filename.  If the filename
3342 * is NULL, use the default owl startup commands file.
3343 */
3344void owl_function_source(char *filename)
3345{
3346  FILE *file;
3347  char buff[LINE];
3348
3349  if (!filename) {
3350    filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
3351    file=fopen(filename, "r");
3352    owl_free(filename);
3353  } else {
3354    file=fopen(filename, "r");
3355  }
3356  if (!file) {
3357    /* just fail silently if it doesn't exist */
3358    return;
3359  }
3360  while (fgets(buff, LINE, file)!=NULL) {
3361    buff[strlen(buff)-1]='\0';
3362    owl_function_command(buff);
3363  }
3364  fclose(file);
3365}
3366
3367void owl_function_change_style(owl_view *v, char *stylename)
3368{
3369  owl_style *s;
3370
3371  s=owl_global_get_style_by_name(&g, stylename);
3372  if (!s) {
3373    owl_function_error("No style named %s", stylename);
3374    return;
3375  }
3376  owl_view_set_style(v, s);
3377  owl_messagelist_invalidate_formats(owl_global_get_msglist(&g));
3378  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
3379  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3380}
3381
3382void owl_function_toggleoneline()
3383{
3384  owl_view *v;
3385  owl_style *s;
3386
3387  v=owl_global_get_current_view(&g);
3388  s=owl_view_get_style(v);
3389
3390  if (!owl_style_matches_name(s, "oneline")) {
3391    owl_function_change_style(v, "oneline");
3392  } else {
3393    owl_function_change_style(v, owl_global_get_default_style(&g));
3394  }
3395
3396  owl_messagelist_invalidate_formats(owl_global_get_msglist(&g));
3397  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
3398  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3399}
3400
3401void owl_function_error(char *fmt, ...)
3402{
3403  va_list ap;
3404  char buff[2048], buff2[2048];
3405  char *date;
3406  time_t now;
3407
3408  now=time(NULL);
3409  date=owl_strdup(ctime(&now));
3410  date[strlen(date)-1]='\0';
3411
3412  va_start(ap, fmt);
3413
3414  vsnprintf(buff, 2048, fmt, ap);
3415  sprintf(buff2, "%s %s", date, buff);
3416  owl_function_debugmsg("ERROR: %s", buff);
3417  if (owl_global_get_curs_msgwin(&g)) {
3418    werase(owl_global_get_curs_msgwin(&g));
3419    waddstr(owl_global_get_curs_msgwin(&g), buff); 
3420    wnoutrefresh(owl_global_get_curs_msgwin(&g));
3421    owl_global_set_needrefresh(&g);
3422  }
3423  owl_errqueue_append_err(owl_global_get_errqueue(&g), buff2);
3424  va_end(ap);
3425  owl_free(date);
3426}
3427
3428void owl_function_showerrs()
3429{
3430  owl_fmtext fm;
3431
3432  owl_fmtext_init_null(&fm);
3433  owl_fmtext_append_normal(&fm, "Errors:\n\n");
3434  owl_errqueue_to_fmtext(owl_global_get_errqueue(&g), &fm);
3435  owl_function_popless_fmtext(&fm);
3436}
3437
3438void owl_function_makemsg(char *fmt, ...)
3439{
3440  va_list ap;
3441  char buff[2048];
3442
3443  if (!owl_global_get_curs_msgwin(&g)) return;
3444
3445  va_start(ap, fmt);
3446  werase(owl_global_get_curs_msgwin(&g));
3447 
3448  vsnprintf(buff, 2048, fmt, ap);
3449  owl_function_debugmsg("makemsg: %s", buff);
3450  waddstr(owl_global_get_curs_msgwin(&g), buff); 
3451  wnoutrefresh(owl_global_get_curs_msgwin(&g));
3452  owl_global_set_needrefresh(&g);
3453  va_end(ap);
3454}
3455
3456/* get locations for everyone in .anyone.  If 'notify' is '1' then
3457 * send a pseudo login or logout message for everyone not in sync with
3458 * the global zephyr buddy list.  The list is updated regardless of
3459 * the status of 'notify'.
3460 */
3461void owl_function_zephyr_buddy_check(int notify)
3462{
3463#ifdef HAVE_LIBZEPHYR
3464  int i, j;
3465  owl_list anyone;
3466  owl_message *m;
3467  owl_zbuddylist *zbl;
3468  char *user;
3469  ZLocations_t location[200];
3470  int numlocs, ret;
3471
3472  zbl=owl_global_get_zephyr_buddylist(&g);
3473
3474  owl_list_create(&anyone);
3475  ret=owl_zephyr_get_anyone_list(&anyone, NULL);
3476
3477  j=owl_list_get_size(&anyone);
3478  for (i=0; i<j; i++) {
3479    user=owl_list_get_element(&anyone, i);
3480    ret=ZLocateUser(user, &numlocs, ZAUTH);
3481    if (ret!=ZERR_NONE) {
3482      owl_function_error("Error getting location for %s", user);
3483      continue;
3484    }
3485    numlocs=200;
3486    ret=ZGetLocations(location, &numlocs);
3487    if (ret==0) {
3488      if ((numlocs>0) && !owl_zbuddylist_contains_user(zbl, user)) {
3489        /* Send a PSEUDO LOGIN! */
3490        if (notify) {
3491          m=owl_malloc(sizeof(owl_message));
3492          owl_message_create_pseudo_zlogin(m, 0, user, location[0].host, location[0].time, location[0].tty);
3493          owl_global_messagequeue_addmsg(&g, m);
3494        }
3495        owl_zbuddylist_adduser(zbl, user);
3496        owl_function_debugmsg("owl_function_zephyr_buddy_check: login for %s ", user);
3497      } else if ((numlocs==0) && owl_zbuddylist_contains_user(zbl, user)) {
3498        /* I don't think this ever happens (if there are 0 locations we should get an error from
3499         * ZGetLocations)
3500         */
3501        owl_function_error("owl_function_zephyr_buddy_check: exceptional case logout for %s ",user);
3502      }
3503    } else if ((ret==ZERR_NOLOCATIONS) && owl_zbuddylist_contains_user(zbl, user)) {
3504      /* Send a PSEUDO LOGOUT! */
3505      if (notify) {
3506        m=owl_malloc(sizeof(owl_message));
3507        owl_message_create_pseudo_zlogin(m, 1, user, "", "", "");
3508        owl_global_messagequeue_addmsg(&g, m);
3509      }
3510      owl_zbuddylist_deluser(zbl, user);
3511      owl_function_debugmsg("owl_function_zephyr_buddy_check: logout for %s ",user);
3512    }
3513  }
3514
3515  owl_list_free_all(&anyone, owl_free);
3516#endif
3517}
3518
3519void owl_function_aimsearch_results(char *email, owl_list *namelist)
3520{
3521  owl_fmtext fm;
3522  int i, j;
3523
3524  owl_fmtext_init_null(&fm);
3525  owl_fmtext_append_normal(&fm, "AIM screennames associated with ");
3526  owl_fmtext_append_normal(&fm, email);
3527  owl_fmtext_append_normal(&fm, ":\n");
3528
3529  j=owl_list_get_size(namelist);
3530  for (i=0; i<j; i++) {
3531    owl_fmtext_append_normal(&fm, "  ");
3532    owl_fmtext_append_normal(&fm, owl_list_get_element(namelist, i));
3533    owl_fmtext_append_normal(&fm, "\n");
3534  }
3535
3536  owl_function_popless_fmtext(&fm);
3537  owl_fmtext_free(&fm);
3538}
Note: See TracBrowser for help on using the repository browser.