source: functions.c @ fea7992

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