source: functions.c @ 9b70dd4

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