source: functions.c @ 4099cf8

barnowl_perlaimdebianrelease-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 4099cf8 was 4099cf8, checked in by Alejandro R. Sedeño <asedeno@mit.edu>, 14 years ago
When generating filters, change single quotes and double quotes into dots, so they line parser doesn't choke on them. This fixes problems smart-narrowing to instances such as "this'll break it".
  • Property mode set to 100644
File size: 100.7 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, single quotes, and double quotes into dots */
2656  owl_text_tr(filtname, ' ', '.');
2657  owl_text_tr(filtname, '\'', '.');
2658  owl_text_tr(filtname, '"', '.');
2659 
2660  /* if it already exists then go with it.  This lets users override */
2661  if (owl_global_get_filter(&g, filtname)) {
2662    return(filtname);
2663  }
2664
2665  /* create the new filter */
2666  tmpclass=owl_text_quote(class, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2667  owl_text_tr(tmpclass, ' ', '.');
2668  owl_text_tr(tmpclass, '\'', '.');
2669  owl_text_tr(tmpclass, '"', '.');
2670  if (instance) {
2671    tmpinstance=owl_text_quote(instance, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2672    owl_text_tr(tmpinstance, ' ', '.');
2673    owl_text_tr(tmpinstance, '\'', '.');
2674    owl_text_tr(tmpinstance, '"', '.');
2675  }
2676  len = strlen(tmpclass);
2677  if(tmpinstance) len += strlen(tmpinstance);
2678  len += 60;
2679  argbuff = owl_malloc(len);
2680  sprintf(argbuff, "class ^(un)*%s(\\.d)*$", tmpclass);
2681  if (tmpinstance) {
2682    sprintf(argbuff, "%s and ( instance ^%s(\\.d)*$ )", argbuff, tmpinstance);
2683  }
2684  owl_free(tmpclass);
2685  if (tmpinstance) owl_free(tmpinstance);
2686
2687  f=owl_malloc(sizeof(owl_filter));
2688  owl_filter_init_fromstring(f, filtname, argbuff);
2689
2690  /* add it to the global list */
2691  owl_global_add_filter(&g, f);
2692
2693  owl_free(argbuff);
2694  owl_free(class);
2695  if (instance) {
2696    owl_free(instance);
2697  }
2698  return(filtname);
2699}
2700
2701/* Create a filter for personal zephyrs to or from the specified
2702 * zephyr user.  Includes login/logout notifications for the user.
2703 * The name of the filter will be 'user-<user>'.  If a filter already
2704 * exists with this name, no new filter will be created.  This allows
2705 * the configuration to override this function.  Returns the name of
2706 * the filter, which the caller must free.
2707 */
2708char *owl_function_zuserfilt(char *user)
2709{
2710  owl_filter *f;
2711  char *argbuff, *longuser, *shortuser, *filtname;
2712
2713  /* stick the local realm on if it's not there */
2714  longuser=long_zuser(user);
2715  shortuser=short_zuser(user);
2716
2717  /* name for the filter */
2718  filtname=owl_malloc(strlen(shortuser)+20);
2719  sprintf(filtname, "user-%s", shortuser);
2720
2721  /* if it already exists then go with it.  This lets users override */
2722  if (owl_global_get_filter(&g, filtname)) {
2723    return(owl_strdup(filtname));
2724  }
2725
2726  /* create the new-internal filter */
2727  f=owl_malloc(sizeof(owl_filter));
2728
2729  argbuff=owl_malloc(strlen(longuser)+1000);
2730  sprintf(argbuff, "( type ^zephyr$ and ( class ^message$ and instance ^personal$ and ");
2731  sprintf(argbuff, "%s ( ( direction ^in$ and sender ^%s$ ) or ( direction ^out$ and recipient ^%s$ ) ) )", argbuff, longuser, longuser);
2732  sprintf(argbuff, "%s or ( ( class ^login$ ) and ( sender ^%s$ ) ) )", argbuff, longuser);
2733
2734  owl_filter_init_fromstring(f, filtname, argbuff);
2735
2736  /* add it to the global list */
2737  owl_global_add_filter(&g, f);
2738
2739  /* free stuff */
2740  owl_free(argbuff);
2741  owl_free(longuser);
2742  owl_free(shortuser);
2743
2744  return(filtname);
2745}
2746
2747/* Create a filter for AIM IM messages to or from the specified
2748 * screenname.  The name of the filter will be 'aimuser-<user>'.  If a
2749 * filter already exists with this name, no new filter will be
2750 * created.  This allows the configuration to override this function.
2751 * Returns the name of the filter, which the caller must free.
2752 */
2753char *owl_function_aimuserfilt(char *user)
2754{
2755  owl_filter *f;
2756  char *argbuff, *filtname;
2757  char *escuser;
2758
2759  /* name for the filter */
2760  filtname=owl_malloc(strlen(user)+40);
2761  sprintf(filtname, "aimuser-%s", user);
2762
2763  /* if it already exists then go with it.  This lets users override */
2764  if (owl_global_get_filter(&g, filtname)) {
2765    return(owl_strdup(filtname));
2766  }
2767
2768  /* create the new-internal filter */
2769  f=owl_malloc(sizeof(owl_filter));
2770
2771  escuser = owl_text_quote(user, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2772
2773  argbuff=owl_malloc(1000);
2774  sprintf(argbuff,
2775          "( type ^aim$ and ( ( sender ^%s$ and recipient ^%s$ ) or ( sender ^%s$ and recipient ^%s$ ) ) )",
2776          escuser, owl_global_get_aim_screenname(&g), owl_global_get_aim_screenname(&g), escuser);
2777
2778  owl_filter_init_fromstring(f, filtname, argbuff);
2779
2780  /* add it to the global list */
2781  owl_global_add_filter(&g, f);
2782
2783  /* free stuff */
2784  owl_free(argbuff);
2785  owl_free(escuser);
2786
2787  return(filtname);
2788}
2789
2790char *owl_function_typefilt(char *type)
2791{
2792  owl_filter *f;
2793  char *argbuff, *filtname;
2794
2795  /* name for the filter */
2796  filtname=owl_sprintf("type-%s", type);
2797
2798  /* if it already exists then go with it.  This lets users override */
2799  if (owl_global_get_filter(&g, filtname)) {
2800    return filtname;
2801  }
2802
2803  /* create the new-internal filter */
2804  f=owl_malloc(sizeof(owl_filter));
2805
2806  argbuff = owl_sprintf("type ^%s$", type);
2807
2808  owl_filter_init_fromstring(f, filtname, argbuff);
2809
2810  /* add it to the global list */
2811  owl_global_add_filter(&g, f);
2812
2813  /* free stuff */
2814  owl_free(argbuff);
2815
2816  return filtname;
2817}
2818
2819/* If flag is 1, marks for deletion.  If flag is 0,
2820 * unmarks for deletion. */
2821void owl_function_delete_curview_msgs(int flag)
2822{
2823  owl_view *v;
2824  int i, j;
2825
2826  v=owl_global_get_current_view(&g);
2827  j=owl_view_get_size(v);
2828  for (i=0; i<j; i++) {
2829    if (flag == 1) {
2830      owl_message_mark_delete(owl_view_get_element(v, i));
2831    } else if (flag == 0) {
2832      owl_message_unmark_delete(owl_view_get_element(v, i));
2833    }
2834  }
2835
2836  owl_function_makemsg("%i messages marked for %sdeletion", j, flag?"":"un");
2837
2838  owl_mainwin_redisplay(owl_global_get_mainwin(&g)); 
2839}
2840
2841/* Create a filter based on the current message.  Returns the name of
2842 * a filter or null.  The caller must free this name.
2843 *
2844 * if the curmsg is a personal zephyr return a filter name
2845 *    to the zephyr converstaion with that user.
2846 * If the curmsg is a zephyr class message, instance foo, recip *,
2847 *    return a filter name to the class, inst.
2848 * If the curmsg is a zephyr class message and type==0 then
2849 *    return a filter name for just the class.
2850 * If the curmsg is a zephyr class message and type==1 then
2851 *    return a filter name for the class and instance.
2852 * If the curmsg is a personal AIM message returna  filter
2853 *    name to the AIM conversation with that user
2854 */
2855char *owl_function_smartfilter(int type)
2856{
2857  owl_view *v;
2858  owl_message *m;
2859  char *zperson, *filtname=NULL;
2860 
2861  v=owl_global_get_current_view(&g);
2862  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2863
2864  if (!m || owl_view_get_size(v)==0) {
2865    owl_function_error("No message selected\n");
2866    return(NULL);
2867  }
2868
2869  /* very simple handling of admin messages for now */
2870  if (owl_message_is_type_admin(m)) {
2871    return(owl_function_typefilt("admin"));
2872  }
2873
2874  /* very simple handling of loopback messages for now */
2875  if (owl_message_is_type_loopback(m)) {
2876    return(owl_function_typefilt("loopback"));
2877  }
2878
2879  /* aim messages */
2880  if (owl_message_is_type_aim(m)) {
2881    if (owl_message_is_direction_in(m)) {
2882      filtname=owl_function_aimuserfilt(owl_message_get_sender(m));
2883    } else if (owl_message_is_direction_out(m)) {
2884      filtname=owl_function_aimuserfilt(owl_message_get_recipient(m));
2885    }
2886    return(filtname);
2887  }
2888
2889  /* narrow personal and login messages to the sender or recip as appropriate */
2890  if (owl_message_is_type_zephyr(m)) {
2891    if (owl_message_is_personal(m) || owl_message_is_loginout(m)) {
2892      if (owl_message_is_direction_in(m)) {
2893        zperson=short_zuser(owl_message_get_sender(m));
2894      } else {
2895        zperson=short_zuser(owl_message_get_recipient(m));
2896      }
2897      filtname=owl_function_zuserfilt(zperson);
2898      owl_free(zperson);
2899      return(filtname);
2900    }
2901
2902    /* narrow class MESSAGE, instance foo, recip * messages to class, inst */
2903    if (!strcasecmp(owl_message_get_class(m), "message") && !owl_message_is_personal(m)) {
2904      filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2905      return(filtname);
2906    }
2907
2908    /* otherwise narrow to the class */
2909    if (type==0) {
2910      filtname=owl_function_classinstfilt(owl_message_get_class(m), NULL);
2911    } else if (type==1) {
2912      filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2913    }
2914    return(filtname);
2915  }
2916
2917  /* pass it off to perl */
2918  char *argv[1];
2919  if(type) {
2920    argv[0] = "-i";
2921  };
2922  return owl_perlconfig_message_call_method(m, "smartfilter", type ? 1 : 0, argv);
2923}
2924
2925void owl_function_smartzpunt(int type)
2926{
2927  /* Starts a zpunt command based on the current class,instance pair.
2928   * If type=0, uses just class.  If type=1, uses instance as well. */
2929  owl_view *v;
2930  owl_message *m;
2931  char *cmd, *cmdprefix, *mclass, *minst;
2932 
2933  v=owl_global_get_current_view(&g);
2934  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2935
2936  if (!m || owl_view_get_size(v)==0) {
2937    owl_function_error("No message selected\n");
2938    return;
2939  }
2940
2941  /* for now we skip admin messages. */
2942  if (owl_message_is_type_admin(m)
2943      || owl_message_is_loginout(m)
2944      || !owl_message_is_type_zephyr(m)) {
2945    owl_function_error("smartzpunt doesn't support this message type.");
2946    return;
2947  }
2948
2949  mclass = owl_message_get_class(m);
2950  minst = owl_message_get_instance(m);
2951  if (!mclass || !*mclass || *mclass==' '
2952      || (!strcasecmp(mclass, "message") && !strcasecmp(minst, "personal"))
2953      || (type && (!minst || !*minst|| *minst==' '))) {
2954    owl_function_error("smartzpunt can't safely do this for <%s,%s>",
2955                         mclass, minst);
2956  } else {
2957    cmdprefix = "start-command zpunt ";
2958    cmd = owl_malloc(strlen(cmdprefix)+strlen(mclass)+strlen(minst)+10);
2959    strcpy(cmd, cmdprefix);
2960    strcat(cmd, owl_getquoting(mclass));
2961    strcat(cmd, mclass);
2962    strcat(cmd, owl_getquoting(mclass));
2963    if (type) {
2964      strcat(cmd, " ");
2965      strcat(cmd, owl_getquoting(minst));
2966      strcat(cmd, minst);
2967      strcat(cmd, owl_getquoting(minst));
2968    } else {
2969      strcat(cmd, " *");
2970    }
2971    owl_function_command(cmd);
2972    owl_free(cmd);
2973  }
2974}
2975
2976/* Set the color of the current view's filter to
2977 * be 'color'
2978 */
2979void owl_function_color_current_filter(char *fgcolor, char *bgcolor)
2980{
2981  char *name;
2982
2983  name=owl_view_get_filtname(owl_global_get_current_view(&g));
2984  owl_function_color_filter(name, fgcolor, bgcolor);
2985}
2986
2987/* Set the color of the filter 'filter' to be 'color'.  If the color
2988 * name does not exist, return -1, if the filter does not exist or is
2989 * the "all" filter, return -2.  Return 0 on success
2990 */
2991int owl_function_color_filter(char *filtname, char *fgcolor, char *bgcolor)
2992{
2993  owl_filter *f;
2994
2995  f=owl_global_get_filter(&g, filtname);
2996  if (!f) {
2997    owl_function_error("Unknown filter");
2998    return(-2);
2999  }
3000
3001  /* don't touch the all filter */
3002  if (!strcmp(filtname, "all")) {
3003    owl_function_error("You may not change the 'all' filter.");
3004    return(-2);
3005  }
3006
3007  if (owl_util_string_to_color(fgcolor)==-1) {
3008    owl_function_error("No color named '%s' avilable.", fgcolor);
3009    return(-1);
3010  }
3011
3012
3013  if (bgcolor != NULL) {
3014    if (owl_util_string_to_color(bgcolor)==-1) {
3015      owl_function_error("No color named '%s' avilable.", bgcolor);
3016      return(-1);
3017    }
3018    owl_filter_set_bgcolor(f, owl_util_string_to_color(bgcolor));
3019  }
3020  owl_filter_set_fgcolor(f, owl_util_string_to_color(fgcolor));
3021 
3022  owl_global_set_needrefresh(&g);
3023  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3024  return(0);
3025}
3026
3027void owl_function_show_colors()
3028{
3029  owl_fmtext fm;
3030  int i; 
3031 
3032  owl_fmtext_init_null(&fm);
3033  owl_fmtext_append_normal(&fm, "default: ");
3034  owl_fmtext_append_normal_color(&fm, "default\n", OWL_COLOR_DEFAULT, OWL_COLOR_DEFAULT);
3035
3036  owl_fmtext_append_normal(&fm,"red:      ");
3037  owl_fmtext_append_normal_color(&fm, "red\n", OWL_COLOR_RED, OWL_COLOR_DEFAULT);
3038
3039  owl_fmtext_append_normal(&fm,"green:    ");
3040  owl_fmtext_append_normal_color(&fm, "green\n", OWL_COLOR_GREEN, OWL_COLOR_DEFAULT);
3041
3042  owl_fmtext_append_normal(&fm,"yellow:   ");
3043  owl_fmtext_append_normal_color(&fm, "yellow\n", OWL_COLOR_YELLOW, OWL_COLOR_DEFAULT);
3044
3045  owl_fmtext_append_normal(&fm,"blue:     ");
3046  owl_fmtext_append_normal_color(&fm, "blue\n", OWL_COLOR_BLUE, OWL_COLOR_DEFAULT);
3047
3048  owl_fmtext_append_normal(&fm,"magenta:  ");
3049  owl_fmtext_append_normal_color(&fm, "magenta\n", OWL_COLOR_MAGENTA, OWL_COLOR_DEFAULT);
3050
3051  owl_fmtext_append_normal(&fm,"cyan:     ");
3052  owl_fmtext_append_normal_color(&fm, "cyan\n", OWL_COLOR_CYAN, OWL_COLOR_DEFAULT);
3053
3054  owl_fmtext_append_normal(&fm,"white:    ");
3055  owl_fmtext_append_normal_color(&fm, "white\n", OWL_COLOR_WHITE, OWL_COLOR_DEFAULT);
3056
3057  for(i = 8; i < COLORS; ++i) {
3058    char* str1 = owl_sprintf("%4i:     ",i);
3059    char* str2 = owl_sprintf("%i\n",i);
3060    owl_fmtext_append_normal(&fm,str1);
3061    owl_fmtext_append_normal_color(&fm, str2, i, OWL_COLOR_DEFAULT);
3062    owl_free(str1);
3063     owl_free(str2);
3064  }
3065 
3066  owl_function_popless_fmtext(&fm);
3067  owl_fmtext_free(&fm);
3068}
3069
3070/* add the given class, inst, recip to the punt list for filtering.
3071 *   if direction==0 then punt
3072 *   if direction==1 then unpunt
3073 */
3074void owl_function_zpunt(char *class, char *inst, char *recip, int direction)
3075{
3076  owl_filter *f;
3077  owl_list *fl;
3078  char *buff;
3079  char *quoted;
3080  int ret, i, j;
3081
3082  fl=owl_global_get_puntlist(&g);
3083
3084  /* first, create the filter */
3085  f=malloc(sizeof(owl_filter));
3086  buff=malloc(strlen(class)+strlen(inst)+strlen(recip)+100);
3087  strcpy(buff, "class");
3088  if (!strcmp(class, "*")) {
3089    strcat(buff, " .*");
3090  } else {
3091    quoted=owl_text_quote(class, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
3092    owl_text_tr(quoted, ' ', '.');
3093    owl_text_tr(quoted, '\'', '.');
3094    owl_text_tr(quoted, '"', '.');
3095    sprintf(buff, "%s ^(un)*%s(\\.d)*$", buff, quoted);
3096    owl_free(quoted);
3097  }
3098  if (!strcmp(inst, "*")) {
3099    strcat(buff, " and instance .*");
3100  } else {
3101    quoted=owl_text_quote(inst, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
3102    owl_text_tr(quoted, ' ', '.');
3103    owl_text_tr(quoted, '\'', '.');
3104    owl_text_tr(quoted, '"', '.');
3105    sprintf(buff, "%s and instance ^(un)*%s(\\.d)*$", buff, quoted);
3106    owl_free(quoted);
3107  }
3108  if (strcmp(recip, "*")) {
3109    quoted=owl_text_quote(recip, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
3110    owl_text_tr(quoted, ' ', '.');
3111    owl_text_tr(quoted, '\'', '.');
3112    owl_text_tr(quoted, '"', '.');
3113    sprintf(buff, "%s and recipient ^%s$", buff, quoted);
3114    owl_free(quoted);
3115  }
3116 
3117  owl_function_debugmsg("About to filter %s", buff);
3118  ret=owl_filter_init_fromstring(f, "punt-filter", buff);
3119  owl_free(buff);
3120  if (ret) {
3121    owl_function_error("Error creating filter for zpunt");
3122    owl_filter_free(f);
3123    return;
3124  }
3125
3126  /* Check for an identical filter */
3127  j=owl_list_get_size(fl);
3128  for (i=0; i<j; i++) {
3129    if (owl_filter_equiv(f, owl_list_get_element(fl, i))) {
3130      /* if we're punting, then just silently bow out on this duplicate */
3131      if (direction==0) {
3132        owl_filter_free(f);
3133        return;
3134      }
3135
3136      /* if we're unpunting, then remove this filter from the puntlist */
3137      if (direction==1) {
3138        owl_filter_free(owl_list_get_element(fl, i));
3139        owl_list_remove_element(fl, i);
3140        return;
3141      }
3142    }
3143  }
3144
3145  /* If we're punting, add the filter to the global punt list */
3146  if (direction==0) {
3147    owl_list_append_element(fl, f);
3148  }
3149}
3150
3151void owl_function_activate_keymap(char *keymap)
3152{
3153  if (!owl_keyhandler_activate(owl_global_get_keyhandler(&g), keymap)) {
3154    owl_function_error("Unable to activate keymap '%s'", keymap);
3155  }
3156}
3157
3158void owl_function_show_keymaps()
3159{
3160  owl_list l;
3161  owl_fmtext fm;
3162  owl_keymap *km;
3163  owl_keyhandler *kh;
3164  int i, numkm;
3165  char *kmname;
3166
3167  kh = owl_global_get_keyhandler(&g);
3168  owl_fmtext_init_null(&fm);
3169  owl_fmtext_append_bold(&fm, "Keymaps:   ");
3170  owl_fmtext_append_normal(&fm, "(use 'show keymap <name>' for details)\n");
3171  owl_keyhandler_get_keymap_names(kh, &l);
3172  owl_fmtext_append_list(&fm, &l, "\n", owl_function_keymap_summary);
3173  owl_fmtext_append_normal(&fm, "\n");
3174
3175  numkm = owl_list_get_size(&l);
3176  for (i=0; i<numkm; i++) {
3177    kmname = owl_list_get_element(&l, i);
3178    km = owl_keyhandler_get_keymap(kh, kmname);
3179    owl_fmtext_append_bold(&fm, "\n\n----------------------------------------------------------------------------------------------------\n\n");
3180    owl_keymap_get_details(km, &fm);   
3181  }
3182  owl_fmtext_append_normal(&fm, "\n");
3183 
3184  owl_function_popless_fmtext(&fm);
3185  owl_keyhandler_keymap_namelist_free(&l);
3186  owl_fmtext_free(&fm);
3187}
3188
3189char *owl_function_keymap_summary(void *name)
3190{
3191  owl_keymap *km
3192    = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
3193  if (km) return owl_keymap_summary(km);
3194  else return(NULL);
3195}
3196
3197/* TODO: implement for real */
3198void owl_function_show_keymap(char *name)
3199{
3200  owl_fmtext fm;
3201  owl_keymap *km;
3202
3203  owl_fmtext_init_null(&fm);
3204  km = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
3205  if (km) {
3206    owl_keymap_get_details(km, &fm);
3207  } else {
3208    owl_fmtext_append_normal(&fm, "No such keymap...\n");
3209  } 
3210  owl_function_popless_fmtext(&fm);
3211  owl_fmtext_free(&fm);
3212}
3213
3214void owl_function_help_for_command(char *cmdname)
3215{
3216  owl_fmtext fm;
3217
3218  owl_fmtext_init_null(&fm);
3219  owl_cmd_get_help(owl_global_get_cmddict(&g), cmdname, &fm);
3220  owl_function_popless_fmtext(&fm); 
3221  owl_fmtext_free(&fm);
3222}
3223
3224void owl_function_search_start(char *string, int direction)
3225{
3226  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
3227  owl_global_set_search_active(&g, string);
3228  owl_function_search_helper(0, direction);
3229}
3230
3231void owl_function_search_continue(int direction)
3232{
3233  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
3234  owl_function_search_helper(1, direction);
3235}
3236
3237void owl_function_search_helper(int mode, int direction)
3238{
3239  /* move to a message that contains the string.  If direction is
3240   * OWL_DIRECTION_DOWNWARDS then search fowards, if direction is
3241   * OWL_DIRECTION_UPWARDS then search backwards.
3242   *
3243   * If mode==0 then it will stay on the current message if it
3244   * contains the string.
3245   */
3246
3247  owl_view *v;
3248  int viewsize, i, curmsg, start;
3249  owl_message *m;
3250
3251  v=owl_global_get_current_view(&g);
3252  viewsize=owl_view_get_size(v);
3253  curmsg=owl_global_get_curmsg(&g);
3254 
3255  if (viewsize==0) {
3256    owl_function_error("No messages present");
3257    return;
3258  }
3259
3260  if (mode==0) {
3261    start=curmsg;
3262  } else if (direction==OWL_DIRECTION_DOWNWARDS) {
3263    start=curmsg+1;
3264  } else {
3265    start=curmsg-1;
3266  }
3267
3268  /* bounds check */
3269  if (start>=viewsize || start<0) {
3270    owl_function_error("No further matches found");
3271    return;
3272  }
3273
3274  for (i=start; i<viewsize && i>=0;) {
3275    m=owl_view_get_element(v, i);
3276    if (owl_message_search(m, owl_global_get_search_string(&g))) {
3277      owl_global_set_curmsg(&g, i);
3278      owl_function_calculate_topmsg(direction);
3279      owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3280      if (direction==OWL_DIRECTION_DOWNWARDS) {
3281        owl_global_set_direction_downwards(&g);
3282      } else {
3283        owl_global_set_direction_upwards(&g);
3284      }
3285      return;
3286    }
3287    if (direction==OWL_DIRECTION_DOWNWARDS) {
3288      i++;
3289    } else {
3290      i--;
3291    }
3292  }
3293  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3294  owl_function_error("No matches found");
3295}
3296
3297/* strips formatting from ztext and returns the unformatted text.
3298 * caller is responsible for freeing. */
3299char *owl_function_ztext_stylestrip(char *zt)
3300{
3301  owl_fmtext fm;
3302  char *plaintext;
3303
3304  owl_fmtext_init_null(&fm);
3305  owl_fmtext_append_ztext(&fm, zt);
3306  plaintext = owl_fmtext_print_plain(&fm);
3307  owl_fmtext_free(&fm);
3308  return(plaintext);
3309}
3310
3311/* Popup a buddylisting.  If filename is NULL use the default .anyone */
3312void owl_function_buddylist(int aim, int zephyr, char *filename)
3313{
3314  int i, j, x, idle;
3315  owl_fmtext fm;
3316  owl_buddylist *bl;
3317  owl_buddy *b;
3318  owl_list anyone;
3319  char *foo, *timestr;
3320#ifdef HAVE_LIBZEPHYR
3321  char *tmp, *user, *line;
3322  ZLocations_t location[200];
3323  int numlocs, ret;
3324#endif
3325
3326  owl_fmtext_init_null(&fm);
3327
3328  /* AIM first */
3329  if (aim && owl_global_is_aimloggedin(&g)) {
3330    bl=owl_global_get_buddylist(&g);
3331
3332    owl_fmtext_append_bold(&fm, "AIM users logged in:\n");
3333    /* we're assuming AIM for now */
3334    j=owl_buddylist_get_size(bl);
3335    for (i=0; i<j; i++) {
3336      b=owl_buddylist_get_buddy_n(bl, i);
3337      idle=owl_buddy_get_idle_time(b);
3338      if (idle!=0) {
3339        timestr=owl_util_minutes_to_timestr(idle);
3340      } else {
3341        timestr=owl_strdup("");
3342      }
3343      foo=owl_sprintf("  %-20.20s %-12.12s\n", owl_buddy_get_name(b), timestr);
3344      owl_fmtext_append_normal(&fm, foo);
3345      owl_free(timestr);
3346      owl_free(foo);
3347    }
3348  }
3349
3350#ifdef HAVE_LIBZEPHYR
3351  if (zephyr) {
3352    if(!owl_global_is_havezephyr(&g)) {
3353      owl_function_error("Zephyr currently not available.");
3354    } else {
3355      owl_fmtext_append_bold(&fm, "Zephyr users logged in:\n");
3356      owl_list_create(&anyone);
3357      ret=owl_zephyr_get_anyone_list(&anyone, filename);
3358      if (ret) {
3359        owl_fmtext_append_normal(&fm, "  Error opening file for zephyr buddies.\n");
3360      } else {
3361        j=owl_list_get_size(&anyone);
3362        for (i=0; i<j; i++) {
3363          user=owl_list_get_element(&anyone, i);
3364          ret=ZLocateUser(user, &numlocs, ZAUTH);
3365          if (ret!=ZERR_NONE) {
3366            owl_function_error("Error getting location for %s", user);
3367            continue;
3368          }
3369
3370          numlocs=200;
3371          ret=ZGetLocations(location, &numlocs);
3372          if (ret==0) {
3373            for (x=0; x<numlocs; x++) {
3374              line=malloc(strlen(location[x].host)+strlen(location[x].time)+strlen(location[x].tty)+100);
3375              tmp=short_zuser(user);
3376              sprintf(line, "  %-10.10s %-24.24s %-12.12s  %20.20s\n",
3377                      tmp,
3378                      location[x].host,
3379                      location[x].tty,
3380                      location[x].time);
3381              owl_fmtext_append_normal(&fm, line);
3382              owl_free(tmp);
3383              owl_free(line);
3384            }
3385            if (numlocs>=200) {
3386              owl_fmtext_append_normal(&fm, "  Too many locations found for this user, truncating.\n");
3387            }
3388          }
3389        }
3390      }
3391      owl_list_free_all(&anyone, owl_free);
3392    } 
3393  }
3394#endif
3395
3396  if(aim && zephyr) {
3397      if(owl_perlconfig_is_function("BarnOwl::Hooks::_get_blist")) {
3398          char * perlblist = owl_perlconfig_execute("BarnOwl::Hooks::_get_blist()");
3399          if(perlblist) {
3400              owl_fmtext_append_ztext(&fm, perlblist);
3401              owl_free(perlblist);
3402          }
3403      }
3404  }
3405 
3406  owl_function_popless_fmtext(&fm);
3407  owl_fmtext_free(&fm);
3408}
3409
3410/* Dump messages in the current view to the file 'filename'. */
3411void owl_function_dump(char *filename) 
3412{
3413  int i, j, count;
3414  owl_message *m;
3415  owl_view *v;
3416  FILE *file;
3417
3418  v=owl_global_get_current_view(&g);
3419
3420  /* in the future make it ask yes/no */
3421  /*
3422  ret=stat(filename, &sbuf);
3423  if (!ret) {
3424    ret=owl_function_askyesno("File exists, continue? [Y/n]");
3425    if (!ret) return;
3426  }
3427  */
3428
3429  file=fopen(filename, "w");
3430  if (!file) {
3431    owl_function_error("Error opening file");
3432    return;
3433  }
3434
3435  count=0;
3436  j=owl_view_get_size(v);
3437  for (i=0; i<j; i++) {
3438    m=owl_view_get_element(v, i);
3439    fputs(owl_message_get_text(m), file);
3440  }
3441  fclose(file);
3442  owl_function_makemsg("Messages dumped to %s", filename);
3443}
3444
3445void owl_function_do_newmsgproc(void)
3446{
3447  if (owl_global_get_newmsgproc(&g) && strcmp(owl_global_get_newmsgproc(&g), "")) {
3448    /* if there's a process out there, we need to check on it */
3449    if (owl_global_get_newmsgproc_pid(&g)) {
3450      owl_function_debugmsg("Checking on newmsgproc pid==%i", owl_global_get_newmsgproc_pid(&g));
3451      owl_function_debugmsg("Waitpid return is %i", waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG));
3452      waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG);
3453      if (waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG)==-1) {
3454        /* it exited */
3455        owl_global_set_newmsgproc_pid(&g, 0);
3456        owl_function_debugmsg("newmsgproc exited");
3457      } else {
3458        owl_function_debugmsg("newmsgproc did not exit");
3459      }
3460    }
3461   
3462    /* if it exited, fork & exec a new one */
3463    if (owl_global_get_newmsgproc_pid(&g)==0) {
3464      int i, myargc;
3465      i=fork();
3466      if (i) {
3467        /* parent set the child's pid */
3468        owl_global_set_newmsgproc_pid(&g, i);
3469        owl_function_debugmsg("I'm the parent and I started a new newmsgproc with pid %i", i);
3470      } else {
3471        /* child exec's the program */
3472        char **parsed;
3473        parsed=owl_parseline(owl_global_get_newmsgproc(&g), &myargc);
3474        if (myargc < 0) {
3475          owl_function_debugmsg("Could not parse newmsgproc '%s': unbalanced quotes?", owl_global_get_newmsgproc(&g));
3476        }
3477        if (myargc <= 0) {
3478          _exit(127);
3479        }
3480        parsed=realloc(parsed, sizeof(*parsed) * (myargc+1));
3481        parsed[myargc] = NULL;
3482       
3483        owl_function_debugmsg("About to exec \"%s\" with %d arguments", parsed[0], myargc);
3484       
3485        execvp(parsed[0], parsed);
3486       
3487       
3488        /* was there an error exec'ing? */
3489        owl_function_debugmsg("Cannot run newmsgproc '%s': cannot exec '%s': %s", 
3490                              owl_global_get_newmsgproc(&g), parsed[0], strerror(errno));
3491        _exit(127);
3492      }
3493    }
3494  }
3495}
3496
3497/* print the xterm escape sequence to raise the window */
3498void owl_function_xterm_raise(void)
3499{
3500  printf("\033[5t");
3501}
3502
3503/* print the xterm escape sequence to deiconify the window */
3504void owl_function_xterm_deiconify(void)
3505{
3506  printf("\033[1t");
3507}
3508
3509/* Add the specified command to the startup file.  Eventually this
3510 * should be clever, and rewriting settings that will obviosly
3511 * override earlier settings with 'set' 'bindkey' and 'alias'
3512 * commands.  For now though we just remove any line that would
3513 * duplicate this one and then append this line to the end of
3514 * startupfile.
3515 */
3516void owl_function_addstartup(char *buff)
3517{
3518  FILE *file;
3519  char *filename;
3520
3521  filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
3522  file=fopen(filename, "a");
3523  if (!file) {
3524    owl_function_error("Error opening startupfile for new command");
3525    owl_free(filename);
3526    return;
3527  }
3528
3529  /* delete earlier copies */
3530  owl_util_file_deleteline(filename, buff, 1);
3531  owl_free(filename);
3532
3533  /* add this line */
3534  fprintf(file, "%s\n", buff);
3535
3536  fclose(file);
3537}
3538
3539/* Remove the specified command from the startup file. */
3540void owl_function_delstartup(char *buff)
3541{
3542  char *filename;
3543  filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
3544  owl_util_file_deleteline(filename, buff, 1);
3545  owl_free(filename);
3546}
3547
3548/* Execute owl commands from the given filename.  If the filename
3549 * is NULL, use the default owl startup commands file.
3550 */
3551void owl_function_source(char *filename)
3552{
3553  FILE *file;
3554  char buff[LINE];
3555
3556  if (!filename) {
3557    filename=owl_sprintf("%s/%s", owl_global_get_homedir(&g), OWL_STARTUP_FILE);
3558    file=fopen(filename, "r");
3559    owl_free(filename);
3560  } else {
3561    file=fopen(filename, "r");
3562  }
3563  if (!file) {
3564    /* just fail silently if it doesn't exist */
3565    return;
3566  }
3567  while (fgets(buff, LINE, file)!=NULL) {
3568    if (buff[0] == '#') continue;
3569    buff[strlen(buff)-1]='\0';
3570    owl_function_command(buff);
3571  }
3572  fclose(file);
3573}
3574
3575void owl_function_change_style(owl_view *v, char *stylename)
3576{
3577  owl_style *s;
3578
3579  s=owl_global_get_style_by_name(&g, stylename);
3580  if (!s) {
3581    owl_function_error("No style named %s", stylename);
3582    return;
3583  }
3584  owl_view_set_style(v, s);
3585  owl_messagelist_invalidate_formats(owl_global_get_msglist(&g));
3586  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
3587  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3588}
3589
3590void owl_function_toggleoneline()
3591{
3592  owl_view *v;
3593  owl_style *s;
3594
3595  v=owl_global_get_current_view(&g);
3596  s=owl_view_get_style(v);
3597
3598  if (!owl_style_matches_name(s, "oneline")) {
3599    owl_function_change_style(v, "oneline");
3600  } else {
3601    owl_function_change_style(v, owl_global_get_default_style(&g));
3602  }
3603
3604  owl_messagelist_invalidate_formats(owl_global_get_msglist(&g));
3605  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
3606  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3607}
3608
3609void owl_function_error(char *fmt, ...)
3610{
3611  va_list ap;
3612  char buff[2048], buff2[2048];
3613  char *date;
3614  time_t now;
3615
3616  now=time(NULL);
3617  date=owl_strdup(ctime(&now));
3618  date[strlen(date)-1]='\0';
3619
3620  va_start(ap, fmt);
3621
3622  vsnprintf(buff, 2048, fmt, ap);
3623  sprintf(buff2, "%s %s", date, buff);
3624  owl_function_debugmsg("ERROR: %s", buff);
3625  if (owl_global_get_curs_msgwin(&g)) {
3626    werase(owl_global_get_curs_msgwin(&g));
3627    waddstr(owl_global_get_curs_msgwin(&g), buff); 
3628    wnoutrefresh(owl_global_get_curs_msgwin(&g));
3629    owl_global_set_needrefresh(&g);
3630  }
3631  owl_errqueue_append_err(owl_global_get_errqueue(&g), buff2);
3632  va_end(ap);
3633  owl_free(date);
3634}
3635
3636void owl_function_showerrs()
3637{
3638  owl_fmtext fm;
3639
3640  owl_fmtext_init_null(&fm);
3641  owl_fmtext_append_normal(&fm, "Errors:\n\n");
3642  owl_errqueue_to_fmtext(owl_global_get_errqueue(&g), &fm);
3643  owl_function_popless_fmtext(&fm);
3644}
3645
3646void owl_function_makemsg(char *fmt, ...)
3647{
3648  va_list ap;
3649  char buff[2048];
3650
3651  if (!owl_global_get_curs_msgwin(&g)) return;
3652
3653  va_start(ap, fmt);
3654  werase(owl_global_get_curs_msgwin(&g));
3655 
3656  vsnprintf(buff, 2048, fmt, ap);
3657  owl_function_debugmsg("makemsg: %s", buff);
3658  waddstr(owl_global_get_curs_msgwin(&g), buff); 
3659  wnoutrefresh(owl_global_get_curs_msgwin(&g));
3660  owl_global_set_needrefresh(&g);
3661  va_end(ap);
3662}
3663
3664/* get locations for everyone in .anyone.  If 'notify' is '1' then
3665 * send a pseudo login or logout message for everyone not in sync with
3666 * the global zephyr buddy list.  The list is updated regardless of
3667 * the status of 'notify'.
3668 */
3669void owl_function_zephyr_buddy_check(int notify)
3670{
3671#ifdef HAVE_LIBZEPHYR
3672  int i, j;
3673  owl_list anyone;
3674  owl_message *m;
3675  owl_zbuddylist *zbl;
3676  char *user;
3677  ZLocations_t location[200];
3678  int numlocs, ret;
3679
3680  zbl=owl_global_get_zephyr_buddylist(&g);
3681
3682  owl_list_create(&anyone);
3683  ret=owl_zephyr_get_anyone_list(&anyone, NULL);
3684
3685  j=owl_list_get_size(&anyone);
3686  for (i=0; i<j; i++) {
3687    user=owl_list_get_element(&anyone, i);
3688    ret=ZLocateUser(user, &numlocs, ZAUTH);
3689    if (ret!=ZERR_NONE) {
3690      owl_function_error("Error getting location for %s", user);
3691      continue;
3692    }
3693    numlocs=200;
3694    ret=ZGetLocations(location, &numlocs);
3695    if (ret==0) {
3696      if ((numlocs>0) && !owl_zbuddylist_contains_user(zbl, user)) {
3697        /* Send a PSEUDO LOGIN! */
3698        if (notify) {
3699          m=owl_malloc(sizeof(owl_message));
3700          owl_message_create_pseudo_zlogin(m, 0, user, location[0].host, location[0].time, location[0].tty);
3701          owl_global_messagequeue_addmsg(&g, m);
3702        }
3703        owl_zbuddylist_adduser(zbl, user);
3704        owl_function_debugmsg("owl_function_zephyr_buddy_check: login for %s ", user);
3705      } else if ((numlocs==0) && owl_zbuddylist_contains_user(zbl, user)) {
3706        /* I don't think this ever happens (if there are 0 locations we should get an error from
3707         * ZGetLocations)
3708         */
3709        owl_function_error("owl_function_zephyr_buddy_check: exceptional case logout for %s ",user);
3710      }
3711    } else if ((ret==ZERR_NOLOCATIONS) && owl_zbuddylist_contains_user(zbl, user)) {
3712      /* Send a PSEUDO LOGOUT! */
3713      if (notify) {
3714        m=owl_malloc(sizeof(owl_message));
3715        owl_message_create_pseudo_zlogin(m, 1, user, "", "", "");
3716        owl_global_messagequeue_addmsg(&g, m);
3717      }
3718      owl_zbuddylist_deluser(zbl, user);
3719      owl_function_debugmsg("owl_function_zephyr_buddy_check: logout for %s ",user);
3720    }
3721  }
3722
3723  owl_list_free_all(&anyone, owl_free);
3724#endif
3725}
3726
3727void owl_function_aimsearch_results(char *email, owl_list *namelist)
3728{
3729  owl_fmtext fm;
3730  int i, j;
3731
3732  owl_fmtext_init_null(&fm);
3733  owl_fmtext_append_normal(&fm, "AIM screennames associated with ");
3734  owl_fmtext_append_normal(&fm, email);
3735  owl_fmtext_append_normal(&fm, ":\n");
3736
3737  j=owl_list_get_size(namelist);
3738  for (i=0; i<j; i++) {
3739    owl_fmtext_append_normal(&fm, "  ");
3740    owl_fmtext_append_normal(&fm, owl_list_get_element(namelist, i));
3741    owl_fmtext_append_normal(&fm, "\n");
3742  }
3743
3744  owl_function_popless_fmtext(&fm);
3745  owl_fmtext_free(&fm);
3746}
3747
3748int owl_function_get_color_count()
3749{
3750     return COLORS;
3751}
Note: See TracBrowser for help on using the repository browser.