source: functions.c @ c2c5c77

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