source: functions.c @ c1d166b

debianrelease-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since c1d166b was c1d166b, checked in by Nelson Elhage <nelhage@mit.edu>, 15 years ago
functions.c: Remove some more sprintf()s Fix owl_function_show_status and owl_function_show_term() this time.
  • Property mode set to 100644
File size: 94.9 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  owl_function_popless_text(
1408    "This is barnowl version " OWL_VERSION_STRING ".\n\n"
1409    "barnowl is a fork of the Owl zephyr client, written and\n"
1410    "maintained by Alejandro Sedeno and Nelson Elhage at the\n"
1411    "Massachusetts Institute of Technology. \n"
1412    "\n"
1413    "Owl was written by James Kretchmar. The first version, 0.5, was\n"
1414    "released in March 2002.\n"
1415    "\n"
1416    "The name 'owl' was chosen in reference to the owls in the\n"
1417    "Harry Potter novels, who are tasked with carrying messages\n"
1418    "between Witches and Wizards. The name 'barnowl' was chosen\n"
1419    "because we feel our owls should live closer to our ponies.\n"
1420    "\n"
1421    "Copyright (c) 2006-2008 The BarnOwl Developers. All rights reserved.\n"
1422    "Copyright (c) 2004 James Kretchmar. All rights reserved.\n"
1423    "Copyright 2002 Massachusetts Institute of Technology\n"
1424    "\n"
1425    "This program is free software. You can redistribute it and/or\n"
1426    "modify under the terms of the Sleepycat License. Use the \n"
1427    "':show license' command to display the full license\n"
1428  );
1429}
1430
1431void owl_function_info()
1432{
1433  owl_message *m;
1434  owl_fmtext fm, attrfm;
1435  owl_view *v;
1436#ifdef HAVE_LIBZEPHYR
1437  ZNotice_t *n;
1438#endif
1439
1440  owl_fmtext_init_null(&fm);
1441 
1442  v=owl_global_get_current_view(&g);
1443  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
1444  if (!m || owl_view_get_size(v)==0) {
1445    owl_function_error("No message selected\n");
1446    return;
1447  }
1448
1449  owl_fmtext_append_bold(&fm, "General Information:\n");
1450  owl_fmtext_appendf_normal(&fm, "  Msg Id    : %i\n", owl_message_get_id(m));
1451
1452  owl_fmtext_append_normal(&fm, "  Type      : ");
1453  owl_fmtext_append_bold(&fm, owl_message_get_type(m));
1454  owl_fmtext_append_normal(&fm, "\n");
1455
1456  if (owl_message_is_direction_in(m)) {
1457    owl_fmtext_append_normal(&fm, "  Direction : in\n");
1458  } else if (owl_message_is_direction_out(m)) {
1459    owl_fmtext_append_normal(&fm, "  Direction : out\n");
1460  } else if (owl_message_is_direction_none(m)) {
1461    owl_fmtext_append_normal(&fm, "  Direction : none\n");
1462  } else {
1463    owl_fmtext_append_normal(&fm, "  Direction : unknown\n");
1464  }
1465
1466  owl_fmtext_appendf_normal(&fm, "  Time      : %s\n", owl_message_get_timestr(m));
1467
1468  if (!owl_message_is_type_admin(m)) {
1469    owl_fmtext_appendf_normal(&fm, "  Sender    : %s\n", owl_message_get_sender(m));
1470    owl_fmtext_appendf_normal(&fm, "  Recipient : %s\n", owl_message_get_recipient(m));
1471  }
1472
1473  if (owl_message_is_type_zephyr(m)) {
1474    owl_fmtext_append_bold(&fm, "\nZephyr Specific Information:\n");
1475   
1476    owl_fmtext_appendf_normal(&fm, "  Class     : %s\n", owl_message_get_class(m));
1477    owl_fmtext_appendf_normal(&fm, "  Instance  : %s\n", owl_message_get_instance(m));
1478    owl_fmtext_appendf_normal(&fm, "  Opcode    : %s\n", owl_message_get_opcode(m));
1479#ifdef HAVE_LIBZEPHYR
1480    if (owl_message_is_direction_in(m)) {
1481      char *ptr, tmpbuff[1024];
1482      int i, j, fields, len;
1483
1484      n=owl_message_get_notice(m);
1485
1486      if (!owl_message_is_pseudo(m)) {
1487        owl_fmtext_append_normal(&fm, "  Kind      : ");
1488        if (n->z_kind==UNSAFE) {
1489          owl_fmtext_append_normal(&fm, "UNSAFE\n");
1490        } else if (n->z_kind==UNACKED) {
1491          owl_fmtext_append_normal(&fm, "UNACKED\n");
1492        } else if (n->z_kind==ACKED) {
1493          owl_fmtext_append_normal(&fm, "ACKED\n");
1494        } else if (n->z_kind==HMACK) {
1495          owl_fmtext_append_normal(&fm, "HMACK\n");
1496        } else if (n->z_kind==HMCTL) {
1497          owl_fmtext_append_normal(&fm, "HMCTL\n");
1498        } else if (n->z_kind==SERVACK) {
1499          owl_fmtext_append_normal(&fm, "SERVACK\n");
1500        } else if (n->z_kind==SERVNAK) {
1501          owl_fmtext_append_normal(&fm, "SERVNACK\n");
1502        } else if (n->z_kind==CLIENTACK) {
1503          owl_fmtext_append_normal(&fm, "CLIENTACK\n");
1504        } else if (n->z_kind==STAT) {
1505          owl_fmtext_append_normal(&fm, "STAT\n");
1506        } else {
1507          owl_fmtext_append_normal(&fm, "ILLEGAL VALUE\n");
1508        }
1509      }
1510      owl_fmtext_appendf_normal(&fm, "  Host      : %s\n", owl_message_get_hostname(m));
1511
1512      if (!owl_message_is_pseudo(m)) {
1513        owl_fmtext_append_normal(&fm, "\n");
1514        owl_fmtext_appendf_normal(&fm, "  Port      : %i\n", ntohs(n->z_port));
1515        owl_fmtext_appendf_normal(&fm, "  Auth      : %s\n", owl_zephyr_get_authstr(n));
1516
1517        /* FIXME make these more descriptive */
1518        owl_fmtext_appendf_normal(&fm, "  Checkd Ath: %i\n", n->z_checked_auth);
1519        owl_fmtext_appendf_normal(&fm, "  Multi notc: %s\n", n->z_multinotice);
1520        owl_fmtext_appendf_normal(&fm, "  Num other : %i\n", n->z_num_other_fields);
1521        owl_fmtext_appendf_normal(&fm, "  Msg Len   : %i\n", n->z_message_len);
1522
1523        fields=owl_zephyr_get_num_fields(n);
1524        owl_fmtext_appendf_normal(&fm, "  Fields    : %i\n", fields);
1525
1526        for (i=0; i<fields; i++) {
1527          ptr=owl_zephyr_get_field_as_utf8(n, i+1);
1528          len=strlen(ptr);
1529          if (len<30) {
1530            strncpy(tmpbuff, ptr, len);
1531            tmpbuff[len]='\0';
1532          } else {
1533            strncpy(tmpbuff, ptr, 30);
1534            tmpbuff[30]='\0';
1535            strcat(tmpbuff, "...");
1536          }
1537          owl_free(ptr);
1538
1539          for (j=0; j<strlen(tmpbuff); j++) {
1540            if (tmpbuff[j]=='\n') tmpbuff[j]='~';
1541            if (tmpbuff[j]=='\r') tmpbuff[j]='!';
1542          }
1543
1544          owl_fmtext_appendf_normal(&fm, "  Field %i   : %s\n", i+1, tmpbuff);
1545        }
1546        owl_fmtext_appendf_normal(&fm, "  Default Fm: %s\n", n->z_default_format);
1547      }
1548
1549    }
1550#endif
1551  }
1552
1553  owl_fmtext_append_bold(&fm, "\nOwl Message Attributes:\n");
1554  owl_message_attributes_tofmtext(m, &attrfm);
1555  owl_fmtext_append_fmtext(&fm, &attrfm);
1556 
1557  owl_function_popless_fmtext(&fm);
1558  owl_fmtext_free(&fm);
1559  owl_fmtext_free(&attrfm);
1560}
1561
1562/* print the current message in a popup window.
1563 * Use the 'default' style regardless of whatever
1564 * style the user may be using
1565 */
1566void owl_function_curmsg_to_popwin()
1567{
1568  owl_popwin *pw;
1569  owl_view *v;
1570  owl_message *m;
1571  owl_style *s;
1572  owl_fmtext fm;
1573
1574  v=owl_global_get_current_view(&g);
1575  s=owl_global_get_style_by_name(&g, "default");
1576  pw=owl_global_get_popwin(&g);
1577
1578  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
1579
1580  if (!m || owl_view_get_size(v)==0) {
1581    owl_function_error("No current message");
1582    return;
1583  }
1584
1585  owl_fmtext_init_null(&fm);
1586  owl_style_get_formattext(s, &fm, m);
1587
1588  owl_function_popless_fmtext(&fm);
1589  owl_fmtext_free(&fm);
1590}
1591
1592void owl_function_page_curmsg(int step)
1593{
1594  /* scroll down or up within the current message IF the message is truncated */
1595
1596  int offset, curmsg, lines;
1597  owl_view *v;
1598  owl_message *m;
1599
1600  offset=owl_global_get_curmsg_vert_offset(&g);
1601  v=owl_global_get_current_view(&g);
1602  curmsg=owl_global_get_curmsg(&g);
1603  m=owl_view_get_element(v, curmsg);
1604  if (!m || owl_view_get_size(v)==0) return;
1605  lines=owl_message_get_numlines(m);
1606
1607  if (offset==0) {
1608    /* Bail if the curmsg isn't the last one displayed */
1609    if (curmsg != owl_mainwin_get_last_msg(owl_global_get_mainwin(&g))) {
1610      owl_function_makemsg("The entire message is already displayed");
1611      return;
1612    }
1613   
1614    /* Bail if we're not truncated */
1615    if (!owl_mainwin_is_curmsg_truncated(owl_global_get_mainwin(&g))) {
1616      owl_function_makemsg("The entire message is already displayed");
1617      return;
1618    }
1619  }
1620 
1621 
1622  /* don't scroll past the last line */
1623  if (step>0) {
1624    if (offset+step > lines-1) {
1625      owl_global_set_curmsg_vert_offset(&g, lines-1);
1626    } else {
1627      owl_global_set_curmsg_vert_offset(&g, offset+step);
1628    }
1629  }
1630
1631  /* would we be before the beginning of the message? */
1632  if (step<0) {
1633    if (offset+step<0) {
1634      owl_global_set_curmsg_vert_offset(&g, 0);
1635    } else {
1636      owl_global_set_curmsg_vert_offset(&g, offset+step);
1637    }
1638  }
1639 
1640  /* redisplay */
1641  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1642  owl_global_set_needrefresh(&g);
1643}
1644
1645void owl_function_resize_typwin(int newsize)
1646{
1647  owl_global_set_typwin_lines(&g, newsize);
1648  owl_function_resize();
1649}
1650
1651void owl_function_typwin_grow()
1652{
1653  int i;
1654
1655  i=owl_global_get_typwin_lines(&g);
1656  owl_function_resize_typwin(i+1);
1657}
1658
1659void owl_function_typwin_shrink()
1660{
1661  int i;
1662
1663  i=owl_global_get_typwin_lines(&g);
1664  if (i>2) {
1665    owl_function_resize_typwin(i-1);
1666  }
1667}
1668
1669void owl_function_mainwin_pagedown()
1670{
1671  int i;
1672
1673  i=owl_mainwin_get_last_msg(owl_global_get_mainwin(&g));
1674  if (i<0) return;
1675  if (owl_mainwin_is_last_msg_truncated(owl_global_get_mainwin(&g))
1676      && (owl_global_get_curmsg(&g) < i)
1677      && (i>0)) {
1678    i--;
1679  }
1680  owl_global_set_curmsg(&g, i);
1681  owl_function_nextmsg();
1682}
1683
1684void owl_function_mainwin_pageup()
1685{
1686  owl_global_set_curmsg(&g, owl_global_get_topmsg(&g));
1687  owl_function_prevmsg();
1688}
1689
1690void owl_function_getsubs()
1691{
1692  char *buff;
1693
1694  buff=owl_zephyr_getsubs();
1695
1696  if (buff) {
1697    owl_function_popless_text(buff);
1698  } else {
1699    owl_function_popless_text("Error getting subscriptions");
1700  }
1701           
1702  owl_free(buff);
1703}
1704
1705#define PABUFLEN 5000
1706void owl_function_printallvars()
1707{
1708  char buff[PABUFLEN], *pos, *name;
1709  owl_list varnames;
1710  int i, numvarnames, rem;
1711
1712  pos = buff;
1713  pos += sprintf(pos, "%-20s = %s\n", "VARIABLE", "VALUE");
1714  pos += sprintf(pos, "%-20s   %s\n",  "--------", "-----");
1715  owl_variable_dict_get_names(owl_global_get_vardict(&g), &varnames);
1716  rem = (buff+PABUFLEN)-pos-1;
1717  numvarnames = owl_list_get_size(&varnames);
1718  for (i=0; i<numvarnames; i++) {
1719    name = owl_list_get_element(&varnames, i);
1720    if (name && name[0]!='_') {
1721      rem = (buff+PABUFLEN)-pos-1;   
1722      pos += snprintf(pos, rem, "\n%-20s = ", name);
1723      rem = (buff+PABUFLEN)-pos-1;   
1724      owl_variable_get_tostring(owl_global_get_vardict(&g), name, pos, rem);
1725      pos = buff+strlen(buff);
1726    }
1727  }
1728  rem = (buff+PABUFLEN)-pos-1;   
1729  snprintf(pos, rem, "\n");
1730  owl_variable_dict_namelist_free(&varnames);
1731 
1732  owl_function_popless_text(buff);
1733}
1734
1735void owl_function_show_variables()
1736{
1737  owl_list varnames;
1738  owl_fmtext fm; 
1739  int i, numvarnames;
1740  char *varname;
1741
1742  owl_fmtext_init_null(&fm);
1743  owl_fmtext_append_bold(&fm, 
1744      "Variables: (use 'show variable <name>' for details)\n");
1745  owl_variable_dict_get_names(owl_global_get_vardict(&g), &varnames);
1746  numvarnames = owl_list_get_size(&varnames);
1747  for (i=0; i<numvarnames; i++) {
1748    varname = owl_list_get_element(&varnames, i);
1749    if (varname && varname[0]!='_') {
1750      owl_variable_describe(owl_global_get_vardict(&g), varname, &fm);
1751    }
1752  }
1753  owl_variable_dict_namelist_free(&varnames);
1754  owl_function_popless_fmtext(&fm);
1755  owl_fmtext_free(&fm);
1756}
1757
1758void owl_function_show_variable(char *name)
1759{
1760  owl_fmtext fm; 
1761
1762  owl_fmtext_init_null(&fm);
1763  owl_variable_get_help(owl_global_get_vardict(&g), name, &fm);
1764  owl_function_popless_fmtext(&fm);
1765  owl_fmtext_free(&fm); 
1766}
1767
1768/* note: this applies to global message list, not to view.
1769 * If flag is 1, deletes.  If flag is 0, undeletes. */
1770void owl_function_delete_by_id(int id, int flag)
1771{
1772  owl_messagelist *ml;
1773  owl_message *m;
1774  ml = owl_global_get_msglist(&g);
1775  m = owl_messagelist_get_by_id(ml, id);
1776  if (m) {
1777    if (flag == 1) {
1778      owl_message_mark_delete(m);
1779    } else if (flag == 0) {
1780      owl_message_unmark_delete(m);
1781    }
1782    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1783    owl_global_set_needrefresh(&g);
1784  } else {
1785    owl_function_error("No message with id %d: unable to mark for (un)delete",id);
1786  }
1787}
1788
1789void owl_function_delete_automsgs()
1790{
1791  /* mark for deletion all messages in the current view that match the
1792   * 'trash' filter */
1793
1794  int i, j, count;
1795  owl_message *m;
1796  owl_view *v;
1797  owl_filter *f;
1798
1799  /* get the trash filter */
1800  f=owl_global_get_filter(&g, "trash");
1801  if (!f) {
1802    owl_function_error("No trash filter defined");
1803    return;
1804  }
1805
1806  v=owl_global_get_current_view(&g);
1807
1808  count=0;
1809  j=owl_view_get_size(v);
1810  for (i=0; i<j; i++) {
1811    m=owl_view_get_element(v, i);
1812    if (owl_filter_message_match(f, m)) {
1813      count++;
1814      owl_message_mark_delete(m);
1815    }
1816  }
1817  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1818  owl_function_makemsg("%i messages marked for deletion", count);
1819  owl_global_set_needrefresh(&g);
1820}
1821
1822void owl_function_status()
1823{
1824  char buff[MAXPATHLEN+1];
1825  time_t start;
1826  int up, days, hours, minutes;
1827  owl_fmtext fm;
1828
1829  owl_fmtext_init_null(&fm);
1830
1831  start=owl_global_get_starttime(&g);
1832
1833  owl_fmtext_append_normal(&fm, "General Information:\n");
1834
1835  owl_fmtext_append_normal(&fm, "  Version: ");
1836  owl_fmtext_append_normal(&fm, OWL_VERSION_STRING);
1837  owl_fmtext_append_normal(&fm, "\n");
1838
1839  owl_fmtext_append_normal(&fm, "  Startup Arguments: ");
1840  owl_fmtext_append_normal(&fm, owl_global_get_startupargs(&g));
1841  owl_fmtext_append_normal(&fm, "\n");
1842
1843  owl_fmtext_append_normal(&fm, "  Current Directory: ");
1844  if(getcwd(buff, MAXPATHLEN) == NULL) {
1845    owl_fmtext_append_normal(&fm, "<Error in getcwd>");
1846  } else {
1847    owl_fmtext_append_normal(&fm, buff);
1848  }
1849  owl_fmtext_append_normal(&fm, "\n");
1850
1851  owl_fmtext_appendf_normal(&fm, "  Startup Time: %s", ctime(&start));
1852
1853  up=owl_global_get_runtime(&g);
1854  days=up/86400;
1855  up-=days*86400;
1856  hours=up/3600;
1857  up-=hours*3600;
1858  minutes=up/60;
1859  up-=minutes*60;
1860  owl_fmtext_appendf_normal(&fm, "  Run Time: %i days %2.2i:%2.2i:%2.2i\n", days, hours, minutes, up);
1861
1862  owl_fmtext_append_normal(&fm, "\nProtocol Options:\n");
1863  owl_fmtext_append_normal(&fm, "  Zephyr included    : ");
1864  if (owl_global_is_havezephyr(&g)) {
1865    owl_fmtext_append_normal(&fm, "yes\n");
1866  } else {
1867    owl_fmtext_append_normal(&fm, "no\n");
1868  }
1869  owl_fmtext_append_normal(&fm, "  AIM included       : yes\n");
1870  owl_fmtext_append_normal(&fm, "  Loopback included  : yes\n");
1871
1872
1873  owl_fmtext_append_normal(&fm, "\nBuild Options:\n");
1874  owl_fmtext_append_normal(&fm, "  Stderr redirection : ");
1875#if OWL_STDERR_REDIR
1876  owl_fmtext_append_normal(&fm, "yes\n");
1877#else
1878  owl_fmtext_append_normal(&fm, "no\n");
1879#endif
1880 
1881
1882  owl_fmtext_append_normal(&fm, "\nAIM Status:\n");
1883  owl_fmtext_append_normal(&fm, "  Logged in: ");
1884  if (owl_global_is_aimloggedin(&g)) {
1885    owl_fmtext_append_normal(&fm, owl_global_get_aim_screenname(&g));
1886    owl_fmtext_append_normal(&fm, "\n");
1887  } else {
1888    owl_fmtext_append_normal(&fm, "(not logged in)\n");
1889  }
1890
1891  owl_fmtext_append_normal(&fm, "  Processing events: ");
1892  if (owl_global_is_doaimevents(&g)) {
1893    owl_fmtext_append_normal(&fm, "yes\n");
1894  } else {
1895    owl_fmtext_append_normal(&fm, "no\n");
1896  }
1897
1898  owl_function_popless_fmtext(&fm);
1899  owl_fmtext_free(&fm);
1900}
1901
1902void owl_function_show_term()
1903{
1904  owl_fmtext fm;
1905
1906  owl_fmtext_init_null(&fm);
1907  owl_fmtext_appendf_normal(&fm, "Terminal Lines: %i\nTerminal Columns: %i\n",
1908          owl_global_get_lines(&g),
1909          owl_global_get_cols(&g));
1910
1911  if (owl_global_get_hascolors(&g)) {
1912    owl_fmtext_append_normal(&fm, "Color: Yes\n");
1913    owl_fmtext_appendf_normal(&fm, "Number of color pairs: %i\n", owl_global_get_colorpairs(&g));
1914    owl_fmtext_appendf_normal(&fm, "Can change colors: %s\n", can_change_color() ? "yes" : "no");
1915  } else {
1916    owl_fmtext_append_normal(&fm, "Color: No\n");
1917  }
1918
1919  owl_function_popless_fmtext(&fm);
1920  owl_fmtext_free(&fm);
1921}
1922
1923/* if type = 0 then normal reply.
1924 * if type = 1 then it's a reply to sender
1925 * if enter = 0 then allow the command to be edited
1926 * if enter = 1 then don't wait for editing
1927 */
1928void owl_function_reply(int type, int enter)
1929{
1930  char *buff=NULL;
1931  owl_message *m;
1932  owl_filter *f;
1933 
1934  if (owl_view_get_size(owl_global_get_current_view(&g))==0) {
1935    owl_function_error("No message selected");
1936  } else {
1937   
1938    m=owl_view_get_element(owl_global_get_current_view(&g), owl_global_get_curmsg(&g));
1939    if (!m) {
1940      owl_function_error("No message selected");
1941      return;
1942    }
1943
1944    /* first check if we catch the reply-lockout filter */
1945    f=owl_global_get_filter(&g, "reply-lockout");
1946    if (f) {
1947      if (owl_filter_message_match(f, m)) {
1948        owl_function_error("Sorry, replies to this message have been disabled by the reply-lockout filter");
1949        return;
1950      }
1951    }
1952
1953    /* then check if it's a question and just bring up the command prompt */
1954    if (owl_message_is_question(m)) {
1955      owl_function_start_command("");
1956      return;
1957    }
1958
1959    char *cmd;
1960    if((type == 0 &&
1961        (cmd=owl_perlconfig_message_call_method(m, "replycmd", 0, NULL))) ||
1962       (type == 1 &&
1963        (cmd=owl_perlconfig_message_call_method(m, "replysendercmd", 0, NULL)))) {
1964      buff = cmd;
1965    }
1966
1967    if(!buff) {
1968        owl_function_error("I don't know how to reply to that message.");
1969        return;
1970    }
1971
1972    if (enter) {
1973      owl_history *hist = owl_global_get_cmd_history(&g);
1974      owl_history_store(hist, buff);
1975      owl_history_reset(hist);
1976      owl_function_command_norv(buff);
1977    } else {
1978      owl_function_start_command(buff);
1979    }
1980    owl_free(buff);
1981  }
1982}
1983
1984void owl_function_zlocate(int argc, char **argv, int auth)
1985{
1986  owl_fmtext fm;
1987  char *ptr, buff[LINE];
1988  int i;
1989
1990  owl_fmtext_init_null(&fm);
1991
1992  for (i=0; i<argc; i++) {
1993    ptr=long_zuser(argv[i]);
1994    owl_zephyr_zlocate(ptr, buff, auth);
1995    owl_fmtext_append_normal(&fm, buff);
1996    owl_free(ptr);
1997  }
1998
1999  owl_function_popless_fmtext(&fm);
2000  owl_fmtext_free(&fm);
2001}
2002
2003void owl_function_start_command(char *line)
2004{
2005  owl_editwin *tw;
2006
2007  tw=owl_global_get_typwin(&g);
2008  owl_global_set_typwin_active(&g);
2009  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, 
2010                        owl_global_get_cmd_history(&g));
2011
2012  owl_editwin_set_locktext(tw, "command: ");
2013  owl_global_set_needrefresh(&g);
2014
2015  owl_editwin_insert_string(tw, line);
2016  owl_editwin_redisplay(tw, 0);
2017
2018  owl_context_set_editline(owl_global_get_context(&g), tw);
2019  owl_function_activate_keymap("editline");
2020}
2021
2022void owl_function_start_question(char *line)
2023{
2024  owl_editwin *tw;
2025
2026  tw=owl_global_get_typwin(&g);
2027  owl_global_set_typwin_active(&g);
2028  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, owl_global_get_cmd_history(&g));
2029
2030  owl_editwin_set_locktext(tw, line);
2031  owl_global_set_needrefresh(&g);
2032
2033  owl_editwin_redisplay(tw, 0);
2034
2035  owl_context_set_editresponse(owl_global_get_context(&g), tw);
2036  owl_function_activate_keymap("editresponse");
2037}
2038
2039void owl_function_start_password(char *line)
2040{
2041  owl_editwin *tw;
2042
2043  tw=owl_global_get_typwin(&g);
2044  owl_global_set_typwin_active(&g);
2045  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, owl_global_get_cmd_history(&g));
2046  owl_editwin_set_echochar(tw, '*');
2047
2048  owl_editwin_set_locktext(tw, line);
2049  owl_global_set_needrefresh(&g);
2050
2051  owl_editwin_redisplay(tw, 0);
2052
2053  owl_context_set_editresponse(owl_global_get_context(&g), tw);
2054  owl_function_activate_keymap("editresponse");
2055}
2056
2057char *owl_function_exec(int argc, char **argv, char *buff, int type)
2058{
2059  /* if type == 1 display in a popup
2060   * if type == 2 display an admin messages
2061   * if type == 0 return output
2062   * else display in a popup
2063   */
2064  char *newbuff, *redirect = " 2>&1 < /dev/null";
2065  char *out, buff2[1024];
2066  int size;
2067  FILE *p;
2068
2069#if OWL_STDERR_REDIR
2070  redirect = " < /dev/null";
2071#endif
2072
2073  if (argc<2) {
2074    owl_function_error("Wrong number of arguments to the exec command");
2075    return NULL;
2076  }
2077
2078  buff = skiptokens(buff, 1);
2079  newbuff = owl_malloc(strlen(buff)+strlen(redirect)+1);
2080  strcpy(newbuff, buff);
2081  strcat(newbuff, redirect);
2082
2083  if (type == 1) {
2084    owl_popexec_new(newbuff);
2085  } else {
2086    p=popen(newbuff, "r");
2087    out=owl_malloc(1024);
2088    size=1024;
2089    strcpy(out, "");
2090    while (fgets(buff2, 1024, p)!=NULL) {
2091      size+=1024;
2092      out=owl_realloc(out, size);
2093      strcat(out, buff2);
2094    }
2095    pclose(p);
2096   
2097    if (type==1) {
2098      owl_function_popless_text(out);
2099    } else if (type==0) {
2100      return out;
2101    } else if (type==2) {
2102      owl_function_adminmsg(buff, out);
2103    } else {
2104      owl_function_popless_text(out);
2105    }
2106    owl_free(out);
2107  }
2108  return NULL;
2109}
2110
2111char *owl_function_perl(int argc, char **argv, char *buff, int type)
2112{
2113  /* if type == 1 display in a popup
2114   * if type == 2 display an admin messages
2115   * if type == 0 return output
2116   * else display in a popup
2117   */
2118  char *perlout;
2119
2120  if (argc<2) {
2121    owl_function_error("Wrong number of arguments to perl command");
2122    return NULL;
2123  }
2124
2125  /* consume first token (argv[0]) */
2126  buff = skiptokens(buff, 1);
2127
2128  perlout = owl_perlconfig_execute(buff);
2129  if (perlout) { 
2130    if (type==1) {
2131      owl_function_popless_text(perlout);
2132    } else if (type==2) {
2133      owl_function_adminmsg(buff, perlout);
2134    } else if (type==0) {
2135      return perlout;
2136    } else {
2137      owl_function_popless_text(perlout);
2138    }
2139    owl_free(perlout);
2140  }
2141  return NULL;
2142}
2143
2144/* Change the filter associated with the current view.
2145 * This also figures out which message in the new filter
2146 * should have the pointer.
2147 */
2148void owl_function_change_currentview_filter(char *filtname)
2149{
2150  owl_view *v;
2151  owl_filter *f;
2152  int curid=-1, newpos, curmsg;
2153  owl_message *curm=NULL;
2154
2155  v=owl_global_get_current_view(&g);
2156
2157  curmsg=owl_global_get_curmsg(&g);
2158  if (curmsg==-1) {
2159    owl_function_debugmsg("Hit the curmsg==-1 case in change_view");
2160  } else {
2161    curm=owl_view_get_element(v, curmsg);
2162    if (curm) {
2163      curid=owl_message_get_id(curm);
2164      owl_view_save_curmsgid(v, curid);
2165    }
2166  }
2167
2168  f=owl_global_get_filter(&g, filtname);
2169  if (!f) {
2170    owl_function_error("Unknown filter %s", filtname);
2171    return;
2172  }
2173
2174  owl_view_new_filter(v, f);
2175
2176  /* Figure out what to set the current message to.
2177   * - If the view we're leaving has messages in it, go to the closest message
2178   *   to the last message pointed to in that view.
2179   * - If the view we're leaving is empty, try to restore the position
2180   *   from the last time we were in the new view.  */
2181  if (curm) {
2182    newpos = owl_view_get_nearest_to_msgid(v, curid);
2183  } else {
2184    newpos = owl_view_get_nearest_to_saved(v);
2185  }
2186
2187  owl_global_set_curmsg(&g, newpos);
2188  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
2189  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2190  owl_global_set_direction_downwards(&g);
2191}
2192
2193/* Create a new filter, or replace an existing one
2194 * with a new definition.
2195 */
2196void owl_function_create_filter(int argc, char **argv)
2197{
2198  owl_filter *f;
2199  owl_view *v;
2200  int ret, inuse=0;
2201
2202  if (argc < 2) {
2203    owl_function_error("Wrong number of arguments to filter command");
2204    return;
2205  }
2206
2207  owl_function_debugmsg("owl_function_create_filter: starting to create filter named %s", argv[1]);
2208
2209  v=owl_global_get_current_view(&g);
2210
2211  /* don't touch the all filter */
2212  if (!strcmp(argv[1], "all")) {
2213    owl_function_error("You may not change the 'all' filter.");
2214    return;
2215  }
2216
2217  /* deal with the case of trying change the filter color */
2218  if (argc==4 && !strcmp(argv[2], "-c")) {
2219    f=owl_global_get_filter(&g, argv[1]);
2220    if (!f) {
2221      owl_function_error("The filter '%s' does not exist.", argv[1]);
2222      return;
2223    }
2224    if (owl_util_string_to_color(argv[3])==OWL_COLOR_INVALID) {
2225      owl_function_error("The color '%s' is not available.", argv[3]);
2226      return;
2227    }
2228    owl_filter_set_fgcolor(f, owl_util_string_to_color(argv[3]));
2229    owl_global_set_needrefresh(&g);
2230    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2231    return;
2232  }
2233  if (argc==4 && !strcmp(argv[2], "-b")) {
2234    f=owl_global_get_filter(&g, argv[1]);
2235    if (!f) {
2236      owl_function_error("The filter '%s' does not exist.", argv[1]);
2237      return;
2238    }
2239    if (owl_util_string_to_color(argv[3])==OWL_COLOR_INVALID) {
2240      owl_function_error("The color '%s' is not available.", argv[3]);
2241      return;
2242    }
2243    owl_filter_set_bgcolor(f, owl_util_string_to_color(argv[3]));
2244    owl_global_set_needrefresh(&g);
2245    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2246    return;
2247  }
2248
2249  /* create the filter and check for errors */
2250  f=owl_malloc(sizeof(owl_filter));
2251  ret=owl_filter_init(f, argv[1], argc-2, argv+2);
2252  if (ret==-1) {
2253    owl_free(f);
2254    owl_function_error("Invalid filter");
2255    return;
2256  }
2257
2258  /* if the named filter is in use by the current view, remember it */
2259  if (!strcmp(owl_view_get_filtname(v), argv[1])) {
2260    inuse=1;
2261  }
2262
2263  /* if the named filter already exists, nuke it */
2264  if (owl_global_get_filter(&g, argv[1])) {
2265    owl_global_remove_filter(&g, argv[1]);
2266  }
2267
2268  /* add the filter */
2269  owl_global_add_filter(&g, f);
2270
2271  /* if it was in use by the current view then update */
2272  if (inuse) {
2273    owl_function_change_currentview_filter(argv[1]);
2274  }
2275  owl_global_set_needrefresh(&g);
2276  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2277}
2278
2279/* If 'filtername' does not start with 'not-' create a filter named
2280 * 'not-<filtername>' defined as "not filter <filtername>".  If the
2281 * filter 'not-<filtername>' already exists, do not overwrite it.  If
2282 * 'filtername' begins with 'not-' and a filter 'filtername' already
2283 * exists, then do nothing.  If the filter 'filtername' does not
2284 * exist, create it and define it as 'not filter <filtername>'
2285 *
2286 * Returns the name of the negated filter, which the caller must free.
2287 */
2288char *owl_function_create_negative_filter(char *filtername)
2289{
2290  char *newname;
2291  owl_filter *tmpfilt;
2292  char *argv[5];
2293
2294  owl_function_debugmsg("owl_function_create_negative_filter");
2295 
2296  if (!strncmp(filtername, "not-", 4)) {
2297    newname=owl_strdup(filtername+4);
2298  } else {
2299    newname=owl_sprintf("not-%s", filtername);
2300  }
2301
2302  tmpfilt=owl_global_get_filter(&g, newname);
2303  if (!tmpfilt) {
2304    argv[0]="filter"; /* anything is fine here */
2305    argv[1]=newname;
2306    argv[2]="not";
2307    argv[3]="filter";
2308    argv[4]=filtername;
2309    owl_function_create_filter(5, argv);
2310  }
2311
2312  owl_function_debugmsg("owl_function_create_negative_filter: returning with %s", newname);
2313  return(newname);
2314}
2315
2316void owl_function_show_filters()
2317{
2318  owl_list *l;
2319  owl_filter *f;
2320  int i, j;
2321  owl_fmtext fm;
2322
2323  owl_fmtext_init_null(&fm);
2324
2325  l=owl_global_get_filterlist(&g);
2326  j=owl_list_get_size(l);
2327
2328  owl_fmtext_append_bold(&fm, "Filters:\n");
2329
2330  for (i=0; i<j; i++) {
2331    f=owl_list_get_element(l, i);
2332    owl_fmtext_append_normal(&fm, "   ");
2333    if (owl_global_get_hascolors(&g)) {
2334      owl_fmtext_append_normal_color(&fm, owl_filter_get_name(f), owl_filter_get_fgcolor(f), owl_filter_get_bgcolor(f));
2335    } else {
2336      owl_fmtext_append_normal(&fm, owl_filter_get_name(f));
2337    }
2338    owl_fmtext_append_normal(&fm, "\n");
2339  }
2340  owl_function_popless_fmtext(&fm);
2341  owl_fmtext_free(&fm);
2342}
2343
2344void owl_function_show_filter(char *name)
2345{
2346  owl_filter *f;
2347  char *buff, *tmp;
2348
2349  f=owl_global_get_filter(&g, name);
2350  if (!f) {
2351    owl_function_error("There is no filter named %s", name);
2352    return;
2353  }
2354  tmp = owl_filter_print(f);
2355  buff = owl_sprintf("%s: %s", owl_filter_get_name(f), tmp);
2356  owl_function_popless_text(buff);
2357  owl_free(buff);
2358  owl_free(tmp);
2359}
2360
2361void owl_function_show_zpunts()
2362{
2363  owl_filter *f;
2364  owl_list *fl;
2365  char buff[5000];
2366  char *tmp;
2367  owl_fmtext fm;
2368  int i, j;
2369
2370  owl_fmtext_init_null(&fm);
2371
2372  fl=owl_global_get_puntlist(&g);
2373  j=owl_list_get_size(fl);
2374  owl_fmtext_append_bold(&fm, "Active zpunt filters:\n");
2375
2376  for (i=0; i<j; i++) {
2377    f=owl_list_get_element(fl, i);
2378    snprintf(buff, sizeof(buff), "[% 2d] ", i+1);
2379    owl_fmtext_append_normal(&fm, buff);
2380    tmp = owl_filter_print(f);
2381    owl_fmtext_append_normal(&fm, tmp);
2382    owl_free(tmp);
2383    owl_fmtext_append_normal(&fm, buff);
2384  }
2385  owl_function_popless_fmtext(&fm);
2386  owl_fmtext_free(&fm);
2387}
2388
2389/* Create a filter for a class, instance if one doesn't exist.  If
2390 * instance is NULL then catch all messgaes in the class.  Returns the
2391 * name of the filter, which the caller must free.
2392 */
2393char *owl_function_classinstfilt(char *c, char *i) 
2394{
2395  owl_list *fl;
2396  owl_filter *f;
2397  char *argbuff, *filtname;
2398  char *tmpclass, *tmpinstance = NULL;
2399  char *class, *instance = NULL;
2400  int len;
2401
2402  class = owl_util_baseclass(c);
2403  if(i) {
2404    instance = owl_util_baseclass(i);
2405  }
2406
2407  fl=owl_global_get_filterlist(&g);
2408
2409  /* name for the filter */
2410  len=strlen(class)+30;
2411  if (instance) len+=strlen(instance);
2412  filtname=owl_malloc(len);
2413  if (!instance) {
2414    sprintf(filtname, "class-%s", class);
2415  } else {
2416    sprintf(filtname, "class-%s-instance-%s", class, instance);
2417  }
2418  /* downcase it */
2419  {
2420    char *temp = g_utf8_strdown(filtname, -1);
2421    if (temp) {
2422      owl_free(filtname);
2423      filtname = temp;
2424    }
2425  }
2426  /* turn spaces, single quotes, and double quotes into dots */
2427  owl_text_tr(filtname, ' ', '.');
2428  owl_text_tr(filtname, '\'', '.');
2429  owl_text_tr(filtname, '"', '.');
2430 
2431  /* if it already exists then go with it.  This lets users override */
2432  if (owl_global_get_filter(&g, filtname)) {
2433    return(filtname);
2434  }
2435
2436  /* create the new filter */
2437  tmpclass=owl_text_quote(class, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2438  owl_text_tr(tmpclass, ' ', '.');
2439  owl_text_tr(tmpclass, '\'', '.');
2440  owl_text_tr(tmpclass, '"', '.');
2441  if (instance) {
2442    tmpinstance=owl_text_quote(instance, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2443    owl_text_tr(tmpinstance, ' ', '.');
2444    owl_text_tr(tmpinstance, '\'', '.');
2445    owl_text_tr(tmpinstance, '"', '.');
2446  }
2447  len = strlen(tmpclass);
2448  if(tmpinstance) len += strlen(tmpinstance);
2449  len += 60;
2450  argbuff = owl_malloc(len);
2451  sprintf(argbuff, "class ^(un)*%s(\\.d)*$", tmpclass);
2452  if (tmpinstance) {
2453    sprintf(argbuff + strlen(argbuff), " and ( instance ^(un)*%s(\\.d)*$ )", tmpinstance);
2454  }
2455  owl_free(tmpclass);
2456  if (tmpinstance) owl_free(tmpinstance);
2457
2458  f=owl_malloc(sizeof(owl_filter));
2459  owl_filter_init_fromstring(f, filtname, argbuff);
2460
2461  /* add it to the global list */
2462  owl_global_add_filter(&g, f);
2463
2464  owl_free(argbuff);
2465  owl_free(class);
2466  if (instance) {
2467    owl_free(instance);
2468  }
2469  return(filtname);
2470}
2471
2472/* Create a filter for personal zephyrs to or from the specified
2473 * zephyr user.  Includes login/logout notifications for the user.
2474 * The name of the filter will be 'user-<user>'.  If a filter already
2475 * exists with this name, no new filter will be created.  This allows
2476 * the configuration to override this function.  Returns the name of
2477 * the filter, which the caller must free.
2478 */
2479char *owl_function_zuserfilt(char *user)
2480{
2481  owl_filter *f;
2482  char *argbuff, *longuser, *esclonguser, *shortuser, *filtname;
2483
2484  /* stick the local realm on if it's not there */
2485  longuser=long_zuser(user);
2486  shortuser=short_zuser(user);
2487
2488  /* name for the filter */
2489  filtname=owl_sprintf("user-%s", shortuser);
2490
2491  /* if it already exists then go with it.  This lets users override */
2492  if (owl_global_get_filter(&g, filtname)) {
2493    return(owl_strdup(filtname));
2494  }
2495
2496  /* create the new-internal filter */
2497  f=owl_malloc(sizeof(owl_filter));
2498
2499  esclonguser = owl_text_quote(longuser, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2500
2501  argbuff=owl_sprintf("( type ^zephyr$ and filter personal and "
2502      "( ( direction ^in$ and sender ^%1$s$ ) or ( direction ^out$ and "
2503      "recipient ^%1$s$ ) ) ) or ( ( class ^login$ ) and ( sender ^%1$s$ ) )",
2504      esclonguser);
2505
2506  owl_filter_init_fromstring(f, filtname, argbuff);
2507
2508  /* add it to the global list */
2509  owl_global_add_filter(&g, f);
2510
2511  /* free stuff */
2512  owl_free(argbuff);
2513  owl_free(longuser);
2514  owl_free(esclonguser);
2515  owl_free(shortuser);
2516
2517  return(filtname);
2518}
2519
2520/* Create a filter for AIM IM messages to or from the specified
2521 * screenname.  The name of the filter will be 'aimuser-<user>'.  If a
2522 * filter already exists with this name, no new filter will be
2523 * created.  This allows the configuration to override this function.
2524 * Returns the name of the filter, which the caller must free.
2525 */
2526char *owl_function_aimuserfilt(char *user)
2527{
2528  owl_filter *f;
2529  char *argbuff, *filtname;
2530  char *escuser;
2531
2532  /* name for the filter */
2533  filtname=owl_sprintf("aimuser-%s", user);
2534
2535  /* if it already exists then go with it.  This lets users override */
2536  if (owl_global_get_filter(&g, filtname)) {
2537    return(owl_strdup(filtname));
2538  }
2539
2540  /* create the new-internal filter */
2541  f=owl_malloc(sizeof(owl_filter));
2542
2543  escuser = owl_text_quote(user, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2544
2545  argbuff = owl_sprintf(
2546      "( type ^aim$ and ( ( sender ^%1$s$ and recipient ^%2$s$ ) or "
2547      "( sender ^%2$s$ and recipient ^%1$s$ ) ) )",
2548      escuser, owl_global_get_aim_screenname_for_filters(&g));
2549
2550  owl_filter_init_fromstring(f, filtname, argbuff);
2551
2552  /* add it to the global list */
2553  owl_global_add_filter(&g, f);
2554
2555  /* free stuff */
2556  owl_free(argbuff);
2557  owl_free(escuser);
2558
2559  return(filtname);
2560}
2561
2562char *owl_function_typefilt(char *type)
2563{
2564  owl_filter *f;
2565  char *argbuff, *filtname, *esctype;
2566
2567  /* name for the filter */
2568  filtname=owl_sprintf("type-%s", type);
2569
2570  /* if it already exists then go with it.  This lets users override */
2571  if (owl_global_get_filter(&g, filtname)) {
2572    return filtname;
2573  }
2574
2575  /* create the new-internal filter */
2576  f=owl_malloc(sizeof(owl_filter));
2577
2578  esctype = owl_text_quote(type, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2579
2580  argbuff = owl_sprintf("type ^%s$", esctype);
2581
2582  owl_filter_init_fromstring(f, filtname, argbuff);
2583
2584  /* add it to the global list */
2585  owl_global_add_filter(&g, f);
2586
2587  /* free stuff */
2588  owl_free(argbuff);
2589  owl_free(esctype);
2590
2591  return filtname;
2592}
2593
2594/* If flag is 1, marks for deletion.  If flag is 0,
2595 * unmarks for deletion. */
2596void owl_function_delete_curview_msgs(int flag)
2597{
2598  owl_view *v;
2599  int i, j;
2600
2601  v=owl_global_get_current_view(&g);
2602  j=owl_view_get_size(v);
2603  for (i=0; i<j; i++) {
2604    if (flag == 1) {
2605      owl_message_mark_delete(owl_view_get_element(v, i));
2606    } else if (flag == 0) {
2607      owl_message_unmark_delete(owl_view_get_element(v, i));
2608    }
2609  }
2610
2611  owl_function_makemsg("%i messages marked for %sdeletion", j, flag?"":"un");
2612
2613  owl_mainwin_redisplay(owl_global_get_mainwin(&g)); 
2614}
2615
2616/* Create a filter based on the current message.  Returns the name of
2617 * a filter or null.  The caller must free this name.
2618 *
2619 * if the curmsg is a personal zephyr return a filter name
2620 *    to the zephyr converstaion with that user.
2621 * If the curmsg is a zephyr class message, instance foo, recip *,
2622 *    return a filter name to the class, inst.
2623 * If the curmsg is a zephyr class message and type==0 then
2624 *    return a filter name for just the class.
2625 * If the curmsg is a zephyr class message and type==1 then
2626 *    return a filter name for the class and instance.
2627 * If the curmsg is a personal AIM message returna  filter
2628 *    name to the AIM conversation with that user
2629 */
2630char *owl_function_smartfilter(int type)
2631{
2632  owl_view *v;
2633  owl_message *m;
2634  char *zperson, *filtname=NULL;
2635  char *argv[1];
2636 
2637  v=owl_global_get_current_view(&g);
2638  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2639
2640  if (!m || owl_view_get_size(v)==0) {
2641    owl_function_error("No message selected\n");
2642    return(NULL);
2643  }
2644
2645  /* very simple handling of admin messages for now */
2646  if (owl_message_is_type_admin(m)) {
2647    return(owl_function_typefilt("admin"));
2648  }
2649
2650  /* very simple handling of loopback messages for now */
2651  if (owl_message_is_type_loopback(m)) {
2652    return(owl_function_typefilt("loopback"));
2653  }
2654
2655  /* aim messages */
2656  if (owl_message_is_type_aim(m)) {
2657    if (owl_message_is_direction_in(m)) {
2658      filtname=owl_function_aimuserfilt(owl_message_get_sender(m));
2659    } else if (owl_message_is_direction_out(m)) {
2660      filtname=owl_function_aimuserfilt(owl_message_get_recipient(m));
2661    }
2662    return(filtname);
2663  }
2664
2665  /* narrow personal and login messages to the sender or recip as appropriate */
2666  if (owl_message_is_type_zephyr(m)) {
2667    if (owl_message_is_personal(m) || owl_message_is_loginout(m)) {
2668      if (owl_message_is_direction_in(m)) {
2669        zperson=short_zuser(owl_message_get_sender(m));
2670      } else {
2671        zperson=short_zuser(owl_message_get_recipient(m));
2672      }
2673      filtname=owl_function_zuserfilt(zperson);
2674      owl_free(zperson);
2675      return(filtname);
2676    }
2677
2678    /* narrow class MESSAGE, instance foo, recip * messages to class, inst */
2679    if (!strcasecmp(owl_message_get_class(m), "message")) {
2680      filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2681      return(filtname);
2682    }
2683
2684    /* otherwise narrow to the class */
2685    if (type==0) {
2686      filtname=owl_function_classinstfilt(owl_message_get_class(m), NULL);
2687    } else if (type==1) {
2688      filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2689    }
2690    return(filtname);
2691  }
2692
2693  /* pass it off to perl */
2694  if(type) {
2695    argv[0] = "-i";
2696  };
2697  return owl_perlconfig_message_call_method(m, "smartfilter", type ? 1 : 0, argv);
2698}
2699
2700void owl_function_smartzpunt(int type)
2701{
2702  /* Starts a zpunt command based on the current class,instance pair.
2703   * If type=0, uses just class.  If type=1, uses instance as well. */
2704  owl_view *v;
2705  owl_message *m;
2706  char *cmd, *cmdprefix, *mclass, *minst;
2707 
2708  v=owl_global_get_current_view(&g);
2709  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2710
2711  if (!m || owl_view_get_size(v)==0) {
2712    owl_function_error("No message selected\n");
2713    return;
2714  }
2715
2716  /* for now we skip admin messages. */
2717  if (owl_message_is_type_admin(m)
2718      || owl_message_is_loginout(m)
2719      || !owl_message_is_type_zephyr(m)) {
2720    owl_function_error("smartzpunt doesn't support this message type.");
2721    return;
2722  }
2723
2724  mclass = owl_message_get_class(m);
2725  minst = owl_message_get_instance(m);
2726  if (!mclass || !*mclass || *mclass==' '
2727      || (!strcasecmp(mclass, "message") && !strcasecmp(minst, "personal"))
2728      || (type && (!minst || !*minst|| *minst==' '))) {
2729    owl_function_error("smartzpunt can't safely do this for <%s,%s>",
2730                         mclass, minst);
2731  } else {
2732    cmdprefix = "start-command zpunt ";
2733    cmd = owl_malloc(strlen(cmdprefix)+strlen(mclass)+strlen(minst)+10);
2734    strcpy(cmd, cmdprefix);
2735    strcat(cmd, owl_getquoting(mclass));
2736    strcat(cmd, mclass);
2737    strcat(cmd, owl_getquoting(mclass));
2738    if (type) {
2739      strcat(cmd, " ");
2740      strcat(cmd, owl_getquoting(minst));
2741      strcat(cmd, minst);
2742      strcat(cmd, owl_getquoting(minst));
2743    } else {
2744      strcat(cmd, " *");
2745    }
2746    owl_function_command(cmd);
2747    owl_free(cmd);
2748  }
2749}
2750
2751/* Set the color of the current view's filter to
2752 * be 'color'
2753 */
2754void owl_function_color_current_filter(char *fgcolor, char *bgcolor)
2755{
2756  char *name;
2757
2758  name=owl_view_get_filtname(owl_global_get_current_view(&g));
2759  owl_function_color_filter(name, fgcolor, bgcolor);
2760}
2761
2762/* Set the color of the filter 'filter' to be 'color'.  If the color
2763 * name does not exist, return -1, if the filter does not exist or is
2764 * the "all" filter, return -2.  Return 0 on success
2765 */
2766int owl_function_color_filter(char *filtname, char *fgcolor, char *bgcolor)
2767{
2768  owl_filter *f;
2769
2770  f=owl_global_get_filter(&g, filtname);
2771  if (!f) {
2772    owl_function_error("Unknown filter");
2773    return(-2);
2774  }
2775
2776  /* don't touch the all filter */
2777  if (!strcmp(filtname, "all")) {
2778    owl_function_error("You may not change the 'all' filter.");
2779    return(-2);
2780  }
2781
2782  if (owl_util_string_to_color(fgcolor)==OWL_COLOR_INVALID) {
2783    owl_function_error("No color named '%s' avilable.", fgcolor);
2784    return(-1);
2785  }
2786
2787
2788  if (bgcolor != NULL) {
2789    if (owl_util_string_to_color(bgcolor)==OWL_COLOR_INVALID) {
2790      owl_function_error("No color named '%s' avilable.", bgcolor);
2791      return(-1);
2792    }
2793    owl_filter_set_bgcolor(f, owl_util_string_to_color(bgcolor));
2794  }
2795  owl_filter_set_fgcolor(f, owl_util_string_to_color(fgcolor));
2796 
2797  owl_global_set_needrefresh(&g);
2798  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2799  return(0);
2800}
2801
2802void owl_function_show_colors()
2803{
2804  owl_fmtext fm;
2805  int i; 
2806 
2807  owl_fmtext_init_null(&fm);
2808  owl_fmtext_append_normal(&fm, "default: ");
2809  owl_fmtext_append_normal_color(&fm, "default\n", OWL_COLOR_DEFAULT, OWL_COLOR_DEFAULT);
2810
2811  owl_fmtext_append_normal(&fm,"red:      ");
2812  owl_fmtext_append_normal_color(&fm, "red\n", OWL_COLOR_RED, OWL_COLOR_DEFAULT);
2813
2814  owl_fmtext_append_normal(&fm,"green:    ");
2815  owl_fmtext_append_normal_color(&fm, "green\n", OWL_COLOR_GREEN, OWL_COLOR_DEFAULT);
2816
2817  owl_fmtext_append_normal(&fm,"yellow:   ");
2818  owl_fmtext_append_normal_color(&fm, "yellow\n", OWL_COLOR_YELLOW, OWL_COLOR_DEFAULT);
2819
2820  owl_fmtext_append_normal(&fm,"blue:     ");
2821  owl_fmtext_append_normal_color(&fm, "blue\n", OWL_COLOR_BLUE, OWL_COLOR_DEFAULT);
2822
2823  owl_fmtext_append_normal(&fm,"magenta:  ");
2824  owl_fmtext_append_normal_color(&fm, "magenta\n", OWL_COLOR_MAGENTA, OWL_COLOR_DEFAULT);
2825
2826  owl_fmtext_append_normal(&fm,"cyan:     ");
2827  owl_fmtext_append_normal_color(&fm, "cyan\n", OWL_COLOR_CYAN, OWL_COLOR_DEFAULT);
2828
2829  owl_fmtext_append_normal(&fm,"white:    ");
2830  owl_fmtext_append_normal_color(&fm, "white\n", OWL_COLOR_WHITE, OWL_COLOR_DEFAULT);
2831
2832  for(i = 8; i < COLORS; ++i) {
2833    char* str1 = owl_sprintf("%4i:     ",i);
2834    char* str2 = owl_sprintf("%i\n",i);
2835    owl_fmtext_append_normal(&fm,str1);
2836    owl_fmtext_append_normal_color(&fm, str2, i, OWL_COLOR_DEFAULT);
2837    owl_free(str1);
2838     owl_free(str2);
2839  }
2840 
2841  owl_function_popless_fmtext(&fm);
2842  owl_fmtext_free(&fm);
2843}
2844
2845/* add the given class, inst, recip to the punt list for filtering.
2846 *   if direction==0 then punt
2847 *   if direction==1 then unpunt
2848 */
2849void owl_function_zpunt(char *class, char *inst, char *recip, int direction)
2850{
2851  char *buff;
2852  char *quoted;
2853
2854  buff=owl_malloc(strlen(class)+strlen(inst)+strlen(recip)+100);
2855  strcpy(buff, "class");
2856  if (!strcmp(class, "*")) {
2857    strcat(buff, " .*");
2858  } else {
2859    quoted=owl_text_quote(class, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2860    owl_text_tr(quoted, ' ', '.');
2861    owl_text_tr(quoted, '\'', '.');
2862    owl_text_tr(quoted, '"', '.');
2863    sprintf(buff + strlen(buff), " ^(un)*%s(\\.d)*$", quoted);
2864    owl_free(quoted);
2865  }
2866  if (!strcmp(inst, "*")) {
2867    strcat(buff, " and instance .*");
2868  } else {
2869    quoted=owl_text_quote(inst, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2870    owl_text_tr(quoted, ' ', '.');
2871    owl_text_tr(quoted, '\'', '.');
2872    owl_text_tr(quoted, '"', '.');
2873    sprintf(buff + strlen(buff), " and instance ^(un)*%s(\\.d)*$", quoted);
2874    owl_free(quoted);
2875  }
2876  if (strcmp(recip, "*")) {
2877    quoted=owl_text_quote(recip, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2878    owl_text_tr(quoted, ' ', '.');
2879    owl_text_tr(quoted, '\'', '.');
2880    owl_text_tr(quoted, '"', '.');
2881    sprintf(buff + strlen(buff), " and recipient ^%s$", quoted);
2882    owl_free(quoted);
2883  }
2884
2885  owl_function_punt(buff, direction);
2886  owl_free(buff);
2887}
2888
2889void owl_function_punt(char *filter, int direction)
2890{
2891  owl_filter *f;
2892  owl_list *fl;
2893  int ret, i, j;
2894  fl=owl_global_get_puntlist(&g);
2895
2896  /* first, create the filter */
2897  f=malloc(sizeof(owl_filter));
2898
2899  owl_function_debugmsg("About to filter %s", filter);
2900  ret=owl_filter_init_fromstring(f, "punt-filter", filter);
2901  if (ret) {
2902    owl_function_error("Error creating filter for zpunt");
2903    owl_filter_free(f);
2904    return;
2905  }
2906
2907  /* Check for an identical filter */
2908  j=owl_list_get_size(fl);
2909  for (i=0; i<j; i++) {
2910    if (owl_filter_equiv(f, owl_list_get_element(fl, i))) {
2911      owl_function_debugmsg("found an equivalent punt filter");
2912      /* if we're punting, then just silently bow out on this duplicate */
2913      if (direction==0) {
2914        owl_filter_free(f);
2915        return;
2916      }
2917
2918      /* if we're unpunting, then remove this filter from the puntlist */
2919      if (direction==1) {
2920        owl_filter_free(owl_list_get_element(fl, i));
2921        owl_list_remove_element(fl, i);
2922        owl_filter_free(f);
2923        return;
2924      }
2925    }
2926  }
2927
2928  owl_function_debugmsg("punting");
2929  /* If we're punting, add the filter to the global punt list */
2930  if (direction==0) {
2931    owl_list_append_element(fl, f);
2932  }
2933}
2934
2935void owl_function_activate_keymap(char *keymap)
2936{
2937  if (!owl_keyhandler_activate(owl_global_get_keyhandler(&g), keymap)) {
2938    owl_function_error("Unable to activate keymap '%s'", keymap);
2939  }
2940}
2941
2942void owl_function_show_keymaps()
2943{
2944  owl_list l;
2945  owl_fmtext fm;
2946  owl_keymap *km;
2947  owl_keyhandler *kh;
2948  int i, numkm;
2949  char *kmname;
2950
2951  kh = owl_global_get_keyhandler(&g);
2952  owl_fmtext_init_null(&fm);
2953  owl_fmtext_append_bold(&fm, "Keymaps:   ");
2954  owl_fmtext_append_normal(&fm, "(use 'show keymap <name>' for details)\n");
2955  owl_keyhandler_get_keymap_names(kh, &l);
2956  owl_fmtext_append_list(&fm, &l, "\n", owl_function_keymap_summary);
2957  owl_fmtext_append_normal(&fm, "\n");
2958
2959  numkm = owl_list_get_size(&l);
2960  for (i=0; i<numkm; i++) {
2961    kmname = owl_list_get_element(&l, i);
2962    km = owl_keyhandler_get_keymap(kh, kmname);
2963    owl_fmtext_append_bold(&fm, "\n\n----------------------------------------------------------------------------------------------------\n\n");
2964    owl_keymap_get_details(km, &fm);   
2965  }
2966  owl_fmtext_append_normal(&fm, "\n");
2967 
2968  owl_function_popless_fmtext(&fm);
2969  owl_keyhandler_keymap_namelist_free(&l);
2970  owl_fmtext_free(&fm);
2971}
2972
2973char *owl_function_keymap_summary(char *name)
2974{
2975  owl_keymap *km
2976    = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
2977  if (km) return owl_keymap_summary(km);
2978  else return(NULL);
2979}
2980
2981/* TODO: implement for real */
2982void owl_function_show_keymap(char *name)
2983{
2984  owl_fmtext fm;
2985  owl_keymap *km;
2986
2987  owl_fmtext_init_null(&fm);
2988  km = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
2989  if (km) {
2990    owl_keymap_get_details(km, &fm);
2991  } else {
2992    owl_fmtext_append_normal(&fm, "No such keymap...\n");
2993  } 
2994  owl_function_popless_fmtext(&fm);
2995  owl_fmtext_free(&fm);
2996}
2997
2998void owl_function_help_for_command(char *cmdname)
2999{
3000  owl_fmtext fm;
3001
3002  owl_fmtext_init_null(&fm);
3003  owl_cmd_get_help(owl_global_get_cmddict(&g), cmdname, &fm);
3004  owl_function_popless_fmtext(&fm); 
3005  owl_fmtext_free(&fm);
3006}
3007
3008void owl_function_search_start(char *string, int direction)
3009{
3010  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
3011  owl_global_set_search_active(&g, string);
3012  owl_function_search_helper(0, direction);
3013}
3014
3015void owl_function_search_continue(int direction)
3016{
3017  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
3018  owl_function_search_helper(1, direction);
3019}
3020
3021void owl_function_search_helper(int mode, int direction)
3022{
3023  /* move to a message that contains the string.  If direction is
3024   * OWL_DIRECTION_DOWNWARDS then search fowards, if direction is
3025   * OWL_DIRECTION_UPWARDS then search backwards.
3026   *
3027   * If mode==0 then it will stay on the current message if it
3028   * contains the string.
3029   */
3030
3031  owl_view *v;
3032  int viewsize, i, curmsg, start;
3033  owl_message *m;
3034
3035  v=owl_global_get_current_view(&g);
3036  viewsize=owl_view_get_size(v);
3037  curmsg=owl_global_get_curmsg(&g);
3038 
3039  if (viewsize==0) {
3040    owl_function_error("No messages present");
3041    return;
3042  }
3043
3044  if (mode==0) {
3045    start=curmsg;
3046  } else if (direction==OWL_DIRECTION_DOWNWARDS) {
3047    start=curmsg+1;
3048  } else {
3049    start=curmsg-1;
3050  }
3051
3052  /* bounds check */
3053  if (start>=viewsize || start<0) {
3054    owl_function_error("No further matches found");
3055    return;
3056  }
3057
3058  for (i=start; i<viewsize && i>=0;) {
3059    m=owl_view_get_element(v, i);
3060    if (owl_message_search(m, owl_global_get_search_string(&g))) {
3061      owl_global_set_curmsg(&g, i);
3062      owl_function_calculate_topmsg(direction);
3063      owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3064      if (direction==OWL_DIRECTION_DOWNWARDS) {
3065        owl_global_set_direction_downwards(&g);
3066      } else {
3067        owl_global_set_direction_upwards(&g);
3068      }
3069      return;
3070    }
3071    if (direction==OWL_DIRECTION_DOWNWARDS) {
3072      i++;
3073    } else {
3074      i--;
3075    }
3076  }
3077  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3078  owl_function_error("No matches found");
3079}
3080
3081/* strips formatting from ztext and returns the unformatted text.
3082 * caller is responsible for freeing. */
3083char *owl_function_ztext_stylestrip(char *zt)
3084{
3085  owl_fmtext fm;
3086  char *plaintext;
3087
3088  owl_fmtext_init_null(&fm);
3089  owl_fmtext_append_ztext(&fm, zt);
3090  plaintext = owl_fmtext_print_plain(&fm);
3091  owl_fmtext_free(&fm);
3092  return(plaintext);
3093}
3094
3095/* Popup a buddylisting.  If filename is NULL use the default .anyone */
3096void owl_function_buddylist(int aim, int zephyr, char *filename)
3097{
3098  int i, j, x, idle;
3099  owl_fmtext fm;
3100  owl_buddylist *bl;
3101  owl_buddy *b;
3102  owl_list anyone;
3103  char *foo, *timestr;
3104#ifdef HAVE_LIBZEPHYR
3105  char *tmp, *user, *line;
3106  ZLocations_t location[200];
3107  int numlocs, ret;
3108#endif
3109
3110  owl_fmtext_init_null(&fm);
3111
3112  /* AIM first */
3113  if (aim && owl_global_is_aimloggedin(&g)) {
3114    bl=owl_global_get_buddylist(&g);
3115
3116    owl_fmtext_append_bold(&fm, "AIM users logged in:\n");
3117    /* we're assuming AIM for now */
3118    j=owl_buddylist_get_size(bl);
3119    for (i=0; i<j; i++) {
3120      b=owl_buddylist_get_buddy_n(bl, i);
3121      idle=owl_buddy_get_idle_time(b);
3122      if (idle!=0) {
3123        timestr=owl_util_minutes_to_timestr(idle);
3124      } else {
3125        timestr=owl_strdup("");
3126      }
3127      foo=owl_sprintf("  %-20.20s %-12.12s\n", owl_buddy_get_name(b), timestr);
3128      owl_fmtext_append_normal(&fm, foo);
3129      owl_free(timestr);
3130      owl_free(foo);
3131    }
3132  }
3133
3134#ifdef HAVE_LIBZEPHYR
3135  if (zephyr) {
3136    if(!owl_global_is_havezephyr(&g)) {
3137      owl_function_error("Zephyr currently not available.");
3138    } else {
3139      owl_fmtext_append_bold(&fm, "Zephyr users logged in:\n");
3140      owl_list_create(&anyone);
3141      ret=owl_zephyr_get_anyone_list(&anyone, filename);
3142      if (ret) {
3143        owl_fmtext_append_normal(&fm, "  Error opening file for zephyr buddies.\n");
3144      } else {
3145        j=owl_list_get_size(&anyone);
3146        for (i=0; i<j; i++) {
3147          user=owl_list_get_element(&anyone, i);
3148          ret=ZLocateUser(user, &numlocs, ZAUTH);
3149          if (ret!=ZERR_NONE) {
3150            owl_function_error("Error getting location for %s", user);
3151            continue;
3152          }
3153
3154          numlocs=200;
3155          ret=ZGetLocations(location, &numlocs);
3156          if (ret==0) {
3157            for (x=0; x<numlocs; x++) {
3158              line=owl_malloc(strlen(location[x].host)+strlen(location[x].time)+strlen(location[x].tty)+100);
3159              tmp=short_zuser(user);
3160              sprintf(line, "  %-10.10s %-24.24s %-12.12s  %20.20s\n",
3161                      tmp,
3162                      location[x].host,
3163                      location[x].tty,
3164                      location[x].time);
3165              owl_fmtext_append_normal(&fm, line);
3166              owl_free(tmp);
3167              owl_free(line);
3168            }
3169            if (numlocs>=200) {
3170              owl_fmtext_append_normal(&fm, "  Too many locations found for this user, truncating.\n");
3171            }
3172          }
3173        }
3174      }
3175      owl_list_free_all(&anyone, owl_free);
3176    } 
3177  }
3178#endif
3179
3180  if(aim && zephyr) {
3181      if(owl_perlconfig_is_function("BarnOwl::Hooks::_get_blist")) {
3182          char * perlblist = owl_perlconfig_execute("BarnOwl::Hooks::_get_blist()");
3183          if(perlblist) {
3184              owl_fmtext_append_ztext(&fm, perlblist);
3185              owl_free(perlblist);
3186          }
3187      }
3188  }
3189 
3190  owl_function_popless_fmtext(&fm);
3191  owl_fmtext_free(&fm);
3192}
3193
3194/* Dump messages in the current view to the file 'filename'. */
3195void owl_function_dump(char *filename) 
3196{
3197  int i, j, count;
3198  owl_message *m;
3199  owl_view *v;
3200  FILE *file;
3201  char *plaintext;
3202
3203  v=owl_global_get_current_view(&g);
3204
3205  /* in the future make it ask yes/no */
3206  /*
3207  ret=stat(filename, &sbuf);
3208  if (!ret) {
3209    ret=owl_function_askyesno("File exists, continue? [Y/n]");
3210    if (!ret) return;
3211  }
3212  */
3213
3214  file=fopen(filename, "w");
3215  if (!file) {
3216    owl_function_error("Error opening file");
3217    return;
3218  }
3219
3220  count=0;
3221  j=owl_view_get_size(v);
3222  for (i=0; i<j; i++) {
3223    m=owl_view_get_element(v, i);
3224    plaintext = owl_strip_format_chars(owl_message_get_text(m));
3225    if (plaintext) {
3226      fputs(plaintext, file);
3227      owl_free(plaintext);
3228    }
3229  }
3230  fclose(file);
3231  owl_function_makemsg("Messages dumped to %s", filename);
3232}
3233
3234void owl_function_do_newmsgproc(void)
3235{
3236  if (owl_global_get_newmsgproc(&g) && strcmp(owl_global_get_newmsgproc(&g), "")) {
3237    /* if there's a process out there, we need to check on it */
3238    if (owl_global_get_newmsgproc_pid(&g)) {
3239      owl_function_debugmsg("Checking on newmsgproc pid==%i", owl_global_get_newmsgproc_pid(&g));
3240      owl_function_debugmsg("Waitpid return is %i", waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG));
3241      waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG);
3242      if (waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG)==-1) {
3243        /* it exited */
3244        owl_global_set_newmsgproc_pid(&g, 0);
3245        owl_function_debugmsg("newmsgproc exited");
3246      } else {
3247        owl_function_debugmsg("newmsgproc did not exit");
3248      }
3249    }
3250   
3251    /* if it exited, fork & exec a new one */
3252    if (owl_global_get_newmsgproc_pid(&g)==0) {
3253      int i, myargc;
3254      i=fork();
3255      if (i) {
3256        /* parent set the child's pid */
3257        owl_global_set_newmsgproc_pid(&g, i);
3258        owl_function_debugmsg("I'm the parent and I started a new newmsgproc with pid %i", i);
3259      } else {
3260        /* child exec's the program */
3261        char **parsed;
3262        parsed=owl_parseline(owl_global_get_newmsgproc(&g), &myargc);
3263        if (myargc < 0) {
3264          owl_function_debugmsg("Could not parse newmsgproc '%s': unbalanced quotes?", owl_global_get_newmsgproc(&g));
3265        }
3266        if (myargc <= 0) {
3267          _exit(127);
3268        }
3269        parsed=owl_realloc(parsed, sizeof(*parsed) * (myargc+1));
3270        parsed[myargc] = NULL;
3271       
3272        owl_function_debugmsg("About to exec \"%s\" with %d arguments", parsed[0], myargc);
3273       
3274        execvp(parsed[0], parsed);
3275       
3276       
3277        /* was there an error exec'ing? */
3278        owl_function_debugmsg("Cannot run newmsgproc '%s': cannot exec '%s': %s", 
3279                              owl_global_get_newmsgproc(&g), parsed[0], strerror(errno));
3280        _exit(127);
3281      }
3282    }
3283  }
3284}
3285
3286/* print the xterm escape sequence to raise the window */
3287void owl_function_xterm_raise(void)
3288{
3289  printf("\033[5t");
3290}
3291
3292/* print the xterm escape sequence to deiconify the window */
3293void owl_function_xterm_deiconify(void)
3294{
3295  printf("\033[1t");
3296}
3297
3298/* Add the specified command to the startup file.  Eventually this
3299 * should be clever, and rewriting settings that will obviosly
3300 * override earlier settings with 'set' 'bindkey' and 'alias'
3301 * commands.  For now though we just remove any line that would
3302 * duplicate this one and then append this line to the end of
3303 * startupfile.
3304 */
3305void owl_function_addstartup(char *buff)
3306{
3307  FILE *file;
3308  char *filename;
3309
3310  filename=owl_global_get_startupfile(&g);
3311  file=fopen(filename, "a");
3312  if (!file) {
3313    owl_function_error("Error opening startupfile for new command");
3314    return;
3315  }
3316
3317  /* delete earlier copies */
3318  owl_util_file_deleteline(filename, buff, 1);
3319
3320  /* add this line */
3321  fprintf(file, "%s\n", buff);
3322
3323  fclose(file);
3324}
3325
3326/* Remove the specified command from the startup file. */
3327void owl_function_delstartup(char *buff)
3328{
3329  char *filename;
3330  filename=owl_global_get_startupfile(&g);
3331  owl_util_file_deleteline(filename, buff, 1);
3332}
3333
3334/* Execute owl commands from the given filename.  If the filename
3335 * is NULL, use the default owl startup commands file.
3336 */
3337void owl_function_source(char *filename)
3338{
3339  FILE *file;
3340  char buff[LINE];
3341  int fail_silent = 0;
3342
3343  if (!filename) {
3344    fail_silent = 1;
3345    filename=owl_global_get_startupfile(&g);
3346  }
3347  file=fopen(filename, "r");
3348  if (!file) {
3349    if (!fail_silent) {
3350      owl_function_error("Error opening file: %s", filename);
3351    }
3352    return;
3353  }
3354  while (fgets(buff, LINE, file)!=NULL) {
3355    if (buff[0] == '#') continue;
3356    buff[strlen(buff)-1]='\0';
3357    owl_function_command(buff);
3358  }
3359  fclose(file);
3360}
3361
3362void owl_function_change_style(owl_view *v, char *stylename)
3363{
3364  owl_style *s;
3365
3366  s=owl_global_get_style_by_name(&g, stylename);
3367  if (!s) {
3368    owl_function_error("No style named %s", stylename);
3369    return;
3370  }
3371  owl_view_set_style(v, s);
3372  owl_messagelist_invalidate_formats(owl_global_get_msglist(&g));
3373  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
3374  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3375}
3376
3377void owl_function_toggleoneline()
3378{
3379  owl_view *v;
3380  owl_style *s;
3381
3382  v=owl_global_get_current_view(&g);
3383  s=owl_view_get_style(v);
3384
3385  if (!owl_style_matches_name(s, "oneline")) {
3386    owl_function_change_style(v, "oneline");
3387  } else {
3388    owl_function_change_style(v, owl_global_get_default_style(&g));
3389  }
3390
3391  owl_messagelist_invalidate_formats(owl_global_get_msglist(&g));
3392  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
3393  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3394}
3395
3396void owl_function_error(char *fmt, ...)
3397{
3398  va_list ap;
3399  char *buff, *buff2;
3400  char *nl;
3401  char *date;
3402  time_t now;
3403
3404  now=time(NULL);
3405  date=owl_strdup(ctime(&now));
3406  date[strlen(date)-1]='\0';
3407
3408  va_start(ap, fmt);
3409
3410  buff = g_strdup_vprintf(fmt, ap);
3411  buff2 = owl_sprintf("%s %s", date, buff);
3412  owl_function_debugmsg("ERROR: %s", buff);
3413  nl = strchr(buff, '\n');
3414  if(nl && *(nl + 1)) {
3415    /* Multiline error */
3416    owl_function_adminmsg("ERROR", buff);
3417  } else {
3418    owl_function_makemsg("[Error] %s", buff);
3419  }
3420  owl_errqueue_append_err(owl_global_get_errqueue(&g), buff2);
3421  va_end(ap);
3422  owl_free(date);
3423  owl_free(buff);
3424  owl_free(buff2);
3425}
3426
3427void owl_function_showerrs()
3428{
3429  owl_fmtext fm;
3430
3431  owl_fmtext_init_null(&fm);
3432  owl_fmtext_append_normal(&fm, "Errors:\n\n");
3433  owl_errqueue_to_fmtext(owl_global_get_errqueue(&g), &fm);
3434  owl_function_popless_fmtext(&fm);
3435}
3436
3437void owl_function_makemsg(char *fmt, ...)
3438{
3439  va_list ap;
3440  char buff[2048];
3441
3442  if (!owl_global_get_curs_msgwin(&g)) return;
3443
3444  va_start(ap, fmt);
3445  werase(owl_global_get_curs_msgwin(&g));
3446 
3447  vsnprintf(buff, 2048, fmt, ap);
3448  owl_function_debugmsg("makemsg: %s", buff);
3449  waddstr(owl_global_get_curs_msgwin(&g), buff); 
3450  wnoutrefresh(owl_global_get_curs_msgwin(&g));
3451  owl_global_set_needrefresh(&g);
3452  va_end(ap);
3453}
3454
3455/* get locations for everyone in .anyone.  If 'notify' is '1' then
3456 * send a pseudo login or logout message for everyone not in sync with
3457 * the global zephyr buddy list.  The list is updated regardless of
3458 * the status of 'notify'.
3459 */
3460void owl_function_zephyr_buddy_check(int notify)
3461{
3462#ifdef HAVE_LIBZEPHYR
3463  int i, j;
3464  owl_list anyone;
3465  owl_message *m;
3466  owl_zbuddylist *zbl;
3467  char *user;
3468  ZLocations_t location[200];
3469  int numlocs, ret;
3470
3471  zbl=owl_global_get_zephyr_buddylist(&g);
3472
3473  owl_list_create(&anyone);
3474  ret=owl_zephyr_get_anyone_list(&anyone, NULL);
3475
3476  j=owl_list_get_size(&anyone);
3477  for (i=0; i<j; i++) {
3478    user=owl_list_get_element(&anyone, i);
3479    ret=ZLocateUser(user, &numlocs, ZAUTH);
3480    if (ret!=ZERR_NONE) {
3481      owl_function_error("Error getting location for %s", user);
3482      continue;
3483    }
3484    numlocs=200;
3485    ret=ZGetLocations(location, &numlocs);
3486    if (ret==0) {
3487      if ((numlocs>0) && !owl_zbuddylist_contains_user(zbl, user)) {
3488        /* Send a PSEUDO LOGIN! */
3489        if (notify) {
3490          m=owl_malloc(sizeof(owl_message));
3491          owl_message_create_pseudo_zlogin(m, 0, user, location[0].host, location[0].time, location[0].tty);
3492          owl_global_messagequeue_addmsg(&g, m);
3493        }
3494        owl_zbuddylist_adduser(zbl, user);
3495        owl_function_debugmsg("owl_function_zephyr_buddy_check: login for %s ", user);
3496      } else if ((numlocs==0) && owl_zbuddylist_contains_user(zbl, user)) {
3497        /* I don't think this ever happens (if there are 0 locations we should get an error from
3498         * ZGetLocations)
3499         */
3500        owl_function_error("owl_function_zephyr_buddy_check: exceptional case logout for %s ",user);
3501      }
3502    } else if ((ret==ZERR_NOLOCATIONS) && owl_zbuddylist_contains_user(zbl, user)) {
3503      /* Send a PSEUDO LOGOUT! */
3504      if (notify) {
3505        m=owl_malloc(sizeof(owl_message));
3506        owl_message_create_pseudo_zlogin(m, 1, user, "", "", "");
3507        owl_global_messagequeue_addmsg(&g, m);
3508      }
3509      owl_zbuddylist_deluser(zbl, user);
3510      owl_function_debugmsg("owl_function_zephyr_buddy_check: logout for %s ",user);
3511    }
3512  }
3513
3514  owl_list_free_all(&anyone, owl_free);
3515#endif
3516}
3517
3518void owl_function_aimsearch_results(char *email, owl_list *namelist)
3519{
3520  owl_fmtext fm;
3521  int i, j;
3522
3523  owl_fmtext_init_null(&fm);
3524  owl_fmtext_append_normal(&fm, "AIM screennames associated with ");
3525  owl_fmtext_append_normal(&fm, email);
3526  owl_fmtext_append_normal(&fm, ":\n");
3527
3528  j=owl_list_get_size(namelist);
3529  for (i=0; i<j; i++) {
3530    owl_fmtext_append_normal(&fm, "  ");
3531    owl_fmtext_append_normal(&fm, owl_list_get_element(namelist, i));
3532    owl_fmtext_append_normal(&fm, "\n");
3533  }
3534
3535  owl_function_popless_fmtext(&fm);
3536  owl_fmtext_free(&fm);
3537}
3538
3539int owl_function_get_color_count()
3540{
3541     return COLORS;
3542}
Note: See TracBrowser for help on using the repository browser.