source: functions.c @ 3f3ee61

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