source: functions.c @ d8671a1

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