source: functions.c @ 57609b3

debianrelease-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 57609b3 was 57609b3, checked in by Nelson Elhage <nelhage@mit.edu>, 12 years ago
owl_function_info: Clean up code using owl_fmtext_appendf_normal This replaces the awkward and potentially unsafe use of sprintf previously present here.
  • Property mode set to 100644
File size: 95.1 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  sprintf(buff, "  Startup Time: %s", ctime(&start));
1852  owl_fmtext_append_normal(&fm, buff);
1853
1854  up=owl_global_get_runtime(&g);
1855  days=up/86400;
1856  up-=days*86400;
1857  hours=up/3600;
1858  up-=hours*3600;
1859  minutes=up/60;
1860  up-=minutes*60;
1861  sprintf(buff, "  Run Time: %i days %2.2i:%2.2i:%2.2i\n", days, hours, minutes, up);
1862  owl_fmtext_append_normal(&fm, buff);
1863
1864  owl_fmtext_append_normal(&fm, "\nProtocol Options:\n");
1865  owl_fmtext_append_normal(&fm, "  Zephyr included    : ");
1866  if (owl_global_is_havezephyr(&g)) {
1867    owl_fmtext_append_normal(&fm, "yes\n");
1868  } else {
1869    owl_fmtext_append_normal(&fm, "no\n");
1870  }
1871  owl_fmtext_append_normal(&fm, "  AIM included       : yes\n");
1872  owl_fmtext_append_normal(&fm, "  Loopback included  : yes\n");
1873
1874
1875  owl_fmtext_append_normal(&fm, "\nBuild Options:\n");
1876  owl_fmtext_append_normal(&fm, "  Stderr redirection : ");
1877#if OWL_STDERR_REDIR
1878  owl_fmtext_append_normal(&fm, "yes\n");
1879#else
1880  owl_fmtext_append_normal(&fm, "no\n");
1881#endif
1882 
1883
1884  owl_fmtext_append_normal(&fm, "\nAIM Status:\n");
1885  owl_fmtext_append_normal(&fm, "  Logged in: ");
1886  if (owl_global_is_aimloggedin(&g)) {
1887    owl_fmtext_append_normal(&fm, owl_global_get_aim_screenname(&g));
1888    owl_fmtext_append_normal(&fm, "\n");
1889  } else {
1890    owl_fmtext_append_normal(&fm, "(not logged in)\n");
1891  }
1892
1893  owl_fmtext_append_normal(&fm, "  Processing events: ");
1894  if (owl_global_is_doaimevents(&g)) {
1895    owl_fmtext_append_normal(&fm, "yes\n");
1896  } else {
1897    owl_fmtext_append_normal(&fm, "no\n");
1898  }
1899
1900  owl_function_popless_fmtext(&fm);
1901  owl_fmtext_free(&fm);
1902}
1903
1904void owl_function_show_term()
1905{
1906  owl_fmtext fm;
1907  char buff[LINE];
1908
1909  owl_fmtext_init_null(&fm);
1910  sprintf(buff, "Terminal Lines: %i\nTerminal Columns: %i\n",
1911          owl_global_get_lines(&g),
1912          owl_global_get_cols(&g));
1913  owl_fmtext_append_normal(&fm, buff);
1914
1915  if (owl_global_get_hascolors(&g)) {
1916    owl_fmtext_append_normal(&fm, "Color: Yes\n");
1917    sprintf(buff, "Number of color pairs: %i\n", owl_global_get_colorpairs(&g));
1918    owl_fmtext_append_normal(&fm, buff);
1919    sprintf(buff, "Can change colors: %s\n", can_change_color() ? "yes" : "no");
1920    owl_fmtext_append_normal(&fm, buff);
1921  } else {
1922    owl_fmtext_append_normal(&fm, "Color: No\n");
1923  }
1924
1925  owl_function_popless_fmtext(&fm);
1926  owl_fmtext_free(&fm);
1927}
1928
1929/* if type = 0 then normal reply.
1930 * if type = 1 then it's a reply to sender
1931 * if enter = 0 then allow the command to be edited
1932 * if enter = 1 then don't wait for editing
1933 */
1934void owl_function_reply(int type, int enter)
1935{
1936  char *buff=NULL;
1937  owl_message *m;
1938  owl_filter *f;
1939 
1940  if (owl_view_get_size(owl_global_get_current_view(&g))==0) {
1941    owl_function_error("No message selected");
1942  } else {
1943   
1944    m=owl_view_get_element(owl_global_get_current_view(&g), owl_global_get_curmsg(&g));
1945    if (!m) {
1946      owl_function_error("No message selected");
1947      return;
1948    }
1949
1950    /* first check if we catch the reply-lockout filter */
1951    f=owl_global_get_filter(&g, "reply-lockout");
1952    if (f) {
1953      if (owl_filter_message_match(f, m)) {
1954        owl_function_error("Sorry, replies to this message have been disabled by the reply-lockout filter");
1955        return;
1956      }
1957    }
1958
1959    /* then check if it's a question and just bring up the command prompt */
1960    if (owl_message_is_question(m)) {
1961      owl_function_start_command("");
1962      return;
1963    }
1964
1965    char *cmd;
1966    if((type == 0 &&
1967        (cmd=owl_perlconfig_message_call_method(m, "replycmd", 0, NULL))) ||
1968       (type == 1 &&
1969        (cmd=owl_perlconfig_message_call_method(m, "replysendercmd", 0, NULL)))) {
1970      buff = cmd;
1971    }
1972
1973    if(!buff) {
1974        owl_function_error("I don't know how to reply to that message.");
1975        return;
1976    }
1977
1978    if (enter) {
1979      owl_history *hist = owl_global_get_cmd_history(&g);
1980      owl_history_store(hist, buff);
1981      owl_history_reset(hist);
1982      owl_function_command_norv(buff);
1983    } else {
1984      owl_function_start_command(buff);
1985    }
1986    owl_free(buff);
1987  }
1988}
1989
1990void owl_function_zlocate(int argc, char **argv, int auth)
1991{
1992  owl_fmtext fm;
1993  char *ptr, buff[LINE];
1994  int i;
1995
1996  owl_fmtext_init_null(&fm);
1997
1998  for (i=0; i<argc; i++) {
1999    ptr=long_zuser(argv[i]);
2000    owl_zephyr_zlocate(ptr, buff, auth);
2001    owl_fmtext_append_normal(&fm, buff);
2002    owl_free(ptr);
2003  }
2004
2005  owl_function_popless_fmtext(&fm);
2006  owl_fmtext_free(&fm);
2007}
2008
2009void owl_function_start_command(char *line)
2010{
2011  owl_editwin *tw;
2012
2013  tw=owl_global_get_typwin(&g);
2014  owl_global_set_typwin_active(&g);
2015  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, 
2016                        owl_global_get_cmd_history(&g));
2017
2018  owl_editwin_set_locktext(tw, "command: ");
2019  owl_global_set_needrefresh(&g);
2020
2021  owl_editwin_insert_string(tw, line);
2022  owl_editwin_redisplay(tw, 0);
2023
2024  owl_context_set_editline(owl_global_get_context(&g), tw);
2025  owl_function_activate_keymap("editline");
2026}
2027
2028void owl_function_start_question(char *line)
2029{
2030  owl_editwin *tw;
2031
2032  tw=owl_global_get_typwin(&g);
2033  owl_global_set_typwin_active(&g);
2034  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, owl_global_get_cmd_history(&g));
2035
2036  owl_editwin_set_locktext(tw, line);
2037  owl_global_set_needrefresh(&g);
2038
2039  owl_editwin_redisplay(tw, 0);
2040
2041  owl_context_set_editresponse(owl_global_get_context(&g), tw);
2042  owl_function_activate_keymap("editresponse");
2043}
2044
2045void owl_function_start_password(char *line)
2046{
2047  owl_editwin *tw;
2048
2049  tw=owl_global_get_typwin(&g);
2050  owl_global_set_typwin_active(&g);
2051  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, owl_global_get_cmd_history(&g));
2052  owl_editwin_set_echochar(tw, '*');
2053
2054  owl_editwin_set_locktext(tw, line);
2055  owl_global_set_needrefresh(&g);
2056
2057  owl_editwin_redisplay(tw, 0);
2058
2059  owl_context_set_editresponse(owl_global_get_context(&g), tw);
2060  owl_function_activate_keymap("editresponse");
2061}
2062
2063char *owl_function_exec(int argc, char **argv, char *buff, int type)
2064{
2065  /* if type == 1 display in a popup
2066   * if type == 2 display an admin messages
2067   * if type == 0 return output
2068   * else display in a popup
2069   */
2070  char *newbuff, *redirect = " 2>&1 < /dev/null";
2071  char *out, buff2[1024];
2072  int size;
2073  FILE *p;
2074
2075#if OWL_STDERR_REDIR
2076  redirect = " < /dev/null";
2077#endif
2078
2079  if (argc<2) {
2080    owl_function_error("Wrong number of arguments to the exec command");
2081    return NULL;
2082  }
2083
2084  buff = skiptokens(buff, 1);
2085  newbuff = owl_malloc(strlen(buff)+strlen(redirect)+1);
2086  strcpy(newbuff, buff);
2087  strcat(newbuff, redirect);
2088
2089  if (type == 1) {
2090    owl_popexec_new(newbuff);
2091  } else {
2092    p=popen(newbuff, "r");
2093    out=owl_malloc(1024);
2094    size=1024;
2095    strcpy(out, "");
2096    while (fgets(buff2, 1024, p)!=NULL) {
2097      size+=1024;
2098      out=owl_realloc(out, size);
2099      strcat(out, buff2);
2100    }
2101    pclose(p);
2102   
2103    if (type==1) {
2104      owl_function_popless_text(out);
2105    } else if (type==0) {
2106      return out;
2107    } else if (type==2) {
2108      owl_function_adminmsg(buff, out);
2109    } else {
2110      owl_function_popless_text(out);
2111    }
2112    owl_free(out);
2113  }
2114  return NULL;
2115}
2116
2117char *owl_function_perl(int argc, char **argv, char *buff, int type)
2118{
2119  /* if type == 1 display in a popup
2120   * if type == 2 display an admin messages
2121   * if type == 0 return output
2122   * else display in a popup
2123   */
2124  char *perlout;
2125
2126  if (argc<2) {
2127    owl_function_error("Wrong number of arguments to perl command");
2128    return NULL;
2129  }
2130
2131  /* consume first token (argv[0]) */
2132  buff = skiptokens(buff, 1);
2133
2134  perlout = owl_perlconfig_execute(buff);
2135  if (perlout) { 
2136    if (type==1) {
2137      owl_function_popless_text(perlout);
2138    } else if (type==2) {
2139      owl_function_adminmsg(buff, perlout);
2140    } else if (type==0) {
2141      return perlout;
2142    } else {
2143      owl_function_popless_text(perlout);
2144    }
2145    owl_free(perlout);
2146  }
2147  return NULL;
2148}
2149
2150/* Change the filter associated with the current view.
2151 * This also figures out which message in the new filter
2152 * should have the pointer.
2153 */
2154void owl_function_change_currentview_filter(char *filtname)
2155{
2156  owl_view *v;
2157  owl_filter *f;
2158  int curid=-1, newpos, curmsg;
2159  owl_message *curm=NULL;
2160
2161  v=owl_global_get_current_view(&g);
2162
2163  curmsg=owl_global_get_curmsg(&g);
2164  if (curmsg==-1) {
2165    owl_function_debugmsg("Hit the curmsg==-1 case in change_view");
2166  } else {
2167    curm=owl_view_get_element(v, curmsg);
2168    if (curm) {
2169      curid=owl_message_get_id(curm);
2170      owl_view_save_curmsgid(v, curid);
2171    }
2172  }
2173
2174  f=owl_global_get_filter(&g, filtname);
2175  if (!f) {
2176    owl_function_error("Unknown filter %s", filtname);
2177    return;
2178  }
2179
2180  owl_view_new_filter(v, f);
2181
2182  /* Figure out what to set the current message to.
2183   * - If the view we're leaving has messages in it, go to the closest message
2184   *   to the last message pointed to in that view.
2185   * - If the view we're leaving is empty, try to restore the position
2186   *   from the last time we were in the new view.  */
2187  if (curm) {
2188    newpos = owl_view_get_nearest_to_msgid(v, curid);
2189  } else {
2190    newpos = owl_view_get_nearest_to_saved(v);
2191  }
2192
2193  owl_global_set_curmsg(&g, newpos);
2194  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
2195  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2196  owl_global_set_direction_downwards(&g);
2197}
2198
2199/* Create a new filter, or replace an existing one
2200 * with a new definition.
2201 */
2202void owl_function_create_filter(int argc, char **argv)
2203{
2204  owl_filter *f;
2205  owl_view *v;
2206  int ret, inuse=0;
2207
2208  if (argc < 2) {
2209    owl_function_error("Wrong number of arguments to filter command");
2210    return;
2211  }
2212
2213  owl_function_debugmsg("owl_function_create_filter: starting to create filter named %s", argv[1]);
2214
2215  v=owl_global_get_current_view(&g);
2216
2217  /* don't touch the all filter */
2218  if (!strcmp(argv[1], "all")) {
2219    owl_function_error("You may not change the 'all' filter.");
2220    return;
2221  }
2222
2223  /* deal with the case of trying change the filter color */
2224  if (argc==4 && !strcmp(argv[2], "-c")) {
2225    f=owl_global_get_filter(&g, argv[1]);
2226    if (!f) {
2227      owl_function_error("The filter '%s' does not exist.", argv[1]);
2228      return;
2229    }
2230    if (owl_util_string_to_color(argv[3])==OWL_COLOR_INVALID) {
2231      owl_function_error("The color '%s' is not available.", argv[3]);
2232      return;
2233    }
2234    owl_filter_set_fgcolor(f, owl_util_string_to_color(argv[3]));
2235    owl_global_set_needrefresh(&g);
2236    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2237    return;
2238  }
2239  if (argc==4 && !strcmp(argv[2], "-b")) {
2240    f=owl_global_get_filter(&g, argv[1]);
2241    if (!f) {
2242      owl_function_error("The filter '%s' does not exist.", argv[1]);
2243      return;
2244    }
2245    if (owl_util_string_to_color(argv[3])==OWL_COLOR_INVALID) {
2246      owl_function_error("The color '%s' is not available.", argv[3]);
2247      return;
2248    }
2249    owl_filter_set_bgcolor(f, owl_util_string_to_color(argv[3]));
2250    owl_global_set_needrefresh(&g);
2251    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2252    return;
2253  }
2254
2255  /* create the filter and check for errors */
2256  f=owl_malloc(sizeof(owl_filter));
2257  ret=owl_filter_init(f, argv[1], argc-2, argv+2);
2258  if (ret==-1) {
2259    owl_free(f);
2260    owl_function_error("Invalid filter");
2261    return;
2262  }
2263
2264  /* if the named filter is in use by the current view, remember it */
2265  if (!strcmp(owl_view_get_filtname(v), argv[1])) {
2266    inuse=1;
2267  }
2268
2269  /* if the named filter already exists, nuke it */
2270  if (owl_global_get_filter(&g, argv[1])) {
2271    owl_global_remove_filter(&g, argv[1]);
2272  }
2273
2274  /* add the filter */
2275  owl_global_add_filter(&g, f);
2276
2277  /* if it was in use by the current view then update */
2278  if (inuse) {
2279    owl_function_change_currentview_filter(argv[1]);
2280  }
2281  owl_global_set_needrefresh(&g);
2282  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2283}
2284
2285/* If 'filtername' does not start with 'not-' create a filter named
2286 * 'not-<filtername>' defined as "not filter <filtername>".  If the
2287 * filter 'not-<filtername>' already exists, do not overwrite it.  If
2288 * 'filtername' begins with 'not-' and a filter 'filtername' already
2289 * exists, then do nothing.  If the filter 'filtername' does not
2290 * exist, create it and define it as 'not filter <filtername>'
2291 *
2292 * Returns the name of the negated filter, which the caller must free.
2293 */
2294char *owl_function_create_negative_filter(char *filtername)
2295{
2296  char *newname;
2297  owl_filter *tmpfilt;
2298  char *argv[5];
2299
2300  owl_function_debugmsg("owl_function_create_negative_filter");
2301 
2302  if (!strncmp(filtername, "not-", 4)) {
2303    newname=owl_strdup(filtername+4);
2304  } else {
2305    newname=owl_sprintf("not-%s", filtername);
2306  }
2307
2308  tmpfilt=owl_global_get_filter(&g, newname);
2309  if (!tmpfilt) {
2310    argv[0]="filter"; /* anything is fine here */
2311    argv[1]=newname;
2312    argv[2]="not";
2313    argv[3]="filter";
2314    argv[4]=filtername;
2315    owl_function_create_filter(5, argv);
2316  }
2317
2318  owl_function_debugmsg("owl_function_create_negative_filter: returning with %s", newname);
2319  return(newname);
2320}
2321
2322void owl_function_show_filters()
2323{
2324  owl_list *l;
2325  owl_filter *f;
2326  int i, j;
2327  owl_fmtext fm;
2328
2329  owl_fmtext_init_null(&fm);
2330
2331  l=owl_global_get_filterlist(&g);
2332  j=owl_list_get_size(l);
2333
2334  owl_fmtext_append_bold(&fm, "Filters:\n");
2335
2336  for (i=0; i<j; i++) {
2337    f=owl_list_get_element(l, i);
2338    owl_fmtext_append_normal(&fm, "   ");
2339    if (owl_global_get_hascolors(&g)) {
2340      owl_fmtext_append_normal_color(&fm, owl_filter_get_name(f), owl_filter_get_fgcolor(f), owl_filter_get_bgcolor(f));
2341    } else {
2342      owl_fmtext_append_normal(&fm, owl_filter_get_name(f));
2343    }
2344    owl_fmtext_append_normal(&fm, "\n");
2345  }
2346  owl_function_popless_fmtext(&fm);
2347  owl_fmtext_free(&fm);
2348}
2349
2350void owl_function_show_filter(char *name)
2351{
2352  owl_filter *f;
2353  char *buff, *tmp;
2354
2355  f=owl_global_get_filter(&g, name);
2356  if (!f) {
2357    owl_function_error("There is no filter named %s", name);
2358    return;
2359  }
2360  tmp = owl_filter_print(f);
2361  buff = owl_sprintf("%s: %s", owl_filter_get_name(f), tmp);
2362  owl_function_popless_text(buff);
2363  owl_free(buff);
2364  owl_free(tmp);
2365}
2366
2367void owl_function_show_zpunts()
2368{
2369  owl_filter *f;
2370  owl_list *fl;
2371  char buff[5000];
2372  char *tmp;
2373  owl_fmtext fm;
2374  int i, j;
2375
2376  owl_fmtext_init_null(&fm);
2377
2378  fl=owl_global_get_puntlist(&g);
2379  j=owl_list_get_size(fl);
2380  owl_fmtext_append_bold(&fm, "Active zpunt filters:\n");
2381
2382  for (i=0; i<j; i++) {
2383    f=owl_list_get_element(fl, i);
2384    snprintf(buff, sizeof(buff), "[% 2d] ", i+1);
2385    owl_fmtext_append_normal(&fm, buff);
2386    tmp = owl_filter_print(f);
2387    owl_fmtext_append_normal(&fm, tmp);
2388    owl_free(tmp);
2389    owl_fmtext_append_normal(&fm, buff);
2390  }
2391  owl_function_popless_fmtext(&fm);
2392  owl_fmtext_free(&fm);
2393}
2394
2395/* Create a filter for a class, instance if one doesn't exist.  If
2396 * instance is NULL then catch all messgaes in the class.  Returns the
2397 * name of the filter, which the caller must free.
2398 */
2399char *owl_function_classinstfilt(char *c, char *i) 
2400{
2401  owl_list *fl;
2402  owl_filter *f;
2403  char *argbuff, *filtname;
2404  char *tmpclass, *tmpinstance = NULL;
2405  char *class, *instance = NULL;
2406  int len;
2407
2408  class = owl_util_baseclass(c);
2409  if(i) {
2410    instance = owl_util_baseclass(i);
2411  }
2412
2413  fl=owl_global_get_filterlist(&g);
2414
2415  /* name for the filter */
2416  len=strlen(class)+30;
2417  if (instance) len+=strlen(instance);
2418  filtname=owl_malloc(len);
2419  if (!instance) {
2420    sprintf(filtname, "class-%s", class);
2421  } else {
2422    sprintf(filtname, "class-%s-instance-%s", class, instance);
2423  }
2424  /* downcase it */
2425  {
2426    char *temp = g_utf8_strdown(filtname, -1);
2427    if (temp) {
2428      owl_free(filtname);
2429      filtname = temp;
2430    }
2431  }
2432  /* turn spaces, single quotes, and double quotes into dots */
2433  owl_text_tr(filtname, ' ', '.');
2434  owl_text_tr(filtname, '\'', '.');
2435  owl_text_tr(filtname, '"', '.');
2436 
2437  /* if it already exists then go with it.  This lets users override */
2438  if (owl_global_get_filter(&g, filtname)) {
2439    return(filtname);
2440  }
2441
2442  /* create the new filter */
2443  tmpclass=owl_text_quote(class, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2444  owl_text_tr(tmpclass, ' ', '.');
2445  owl_text_tr(tmpclass, '\'', '.');
2446  owl_text_tr(tmpclass, '"', '.');
2447  if (instance) {
2448    tmpinstance=owl_text_quote(instance, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2449    owl_text_tr(tmpinstance, ' ', '.');
2450    owl_text_tr(tmpinstance, '\'', '.');
2451    owl_text_tr(tmpinstance, '"', '.');
2452  }
2453  len = strlen(tmpclass);
2454  if(tmpinstance) len += strlen(tmpinstance);
2455  len += 60;
2456  argbuff = owl_malloc(len);
2457  sprintf(argbuff, "class ^(un)*%s(\\.d)*$", tmpclass);
2458  if (tmpinstance) {
2459    sprintf(argbuff + strlen(argbuff), " and ( instance ^(un)*%s(\\.d)*$ )", tmpinstance);
2460  }
2461  owl_free(tmpclass);
2462  if (tmpinstance) owl_free(tmpinstance);
2463
2464  f=owl_malloc(sizeof(owl_filter));
2465  owl_filter_init_fromstring(f, filtname, argbuff);
2466
2467  /* add it to the global list */
2468  owl_global_add_filter(&g, f);
2469
2470  owl_free(argbuff);
2471  owl_free(class);
2472  if (instance) {
2473    owl_free(instance);
2474  }
2475  return(filtname);
2476}
2477
2478/* Create a filter for personal zephyrs to or from the specified
2479 * zephyr user.  Includes login/logout notifications for the user.
2480 * The name of the filter will be 'user-<user>'.  If a filter already
2481 * exists with this name, no new filter will be created.  This allows
2482 * the configuration to override this function.  Returns the name of
2483 * the filter, which the caller must free.
2484 */
2485char *owl_function_zuserfilt(char *user)
2486{
2487  owl_filter *f;
2488  char *argbuff, *longuser, *esclonguser, *shortuser, *filtname;
2489
2490  /* stick the local realm on if it's not there */
2491  longuser=long_zuser(user);
2492  shortuser=short_zuser(user);
2493
2494  /* name for the filter */
2495  filtname=owl_sprintf("user-%s", shortuser);
2496
2497  /* if it already exists then go with it.  This lets users override */
2498  if (owl_global_get_filter(&g, filtname)) {
2499    return(owl_strdup(filtname));
2500  }
2501
2502  /* create the new-internal filter */
2503  f=owl_malloc(sizeof(owl_filter));
2504
2505  esclonguser = owl_text_quote(longuser, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2506
2507  argbuff=owl_sprintf("( type ^zephyr$ and filter personal and "
2508      "( ( direction ^in$ and sender ^%1$s$ ) or ( direction ^out$ and "
2509      "recipient ^%1$s$ ) ) ) or ( ( class ^login$ ) and ( sender ^%1$s$ ) )",
2510      esclonguser);
2511
2512  owl_filter_init_fromstring(f, filtname, argbuff);
2513
2514  /* add it to the global list */
2515  owl_global_add_filter(&g, f);
2516
2517  /* free stuff */
2518  owl_free(argbuff);
2519  owl_free(longuser);
2520  owl_free(esclonguser);
2521  owl_free(shortuser);
2522
2523  return(filtname);
2524}
2525
2526/* Create a filter for AIM IM messages to or from the specified
2527 * screenname.  The name of the filter will be 'aimuser-<user>'.  If a
2528 * filter already exists with this name, no new filter will be
2529 * created.  This allows the configuration to override this function.
2530 * Returns the name of the filter, which the caller must free.
2531 */
2532char *owl_function_aimuserfilt(char *user)
2533{
2534  owl_filter *f;
2535  char *argbuff, *filtname;
2536  char *escuser;
2537
2538  /* name for the filter */
2539  filtname=owl_sprintf("aimuser-%s", user);
2540
2541  /* if it already exists then go with it.  This lets users override */
2542  if (owl_global_get_filter(&g, filtname)) {
2543    return(owl_strdup(filtname));
2544  }
2545
2546  /* create the new-internal filter */
2547  f=owl_malloc(sizeof(owl_filter));
2548
2549  escuser = owl_text_quote(user, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2550
2551  argbuff = owl_sprintf(
2552      "( type ^aim$ and ( ( sender ^%1$s$ and recipient ^%2$s$ ) or "
2553      "( sender ^%2$s$ and recipient ^%1$s$ ) ) )",
2554      escuser, owl_global_get_aim_screenname_for_filters(&g));
2555
2556  owl_filter_init_fromstring(f, filtname, argbuff);
2557
2558  /* add it to the global list */
2559  owl_global_add_filter(&g, f);
2560
2561  /* free stuff */
2562  owl_free(argbuff);
2563  owl_free(escuser);
2564
2565  return(filtname);
2566}
2567
2568char *owl_function_typefilt(char *type)
2569{
2570  owl_filter *f;
2571  char *argbuff, *filtname, *esctype;
2572
2573  /* name for the filter */
2574  filtname=owl_sprintf("type-%s", type);
2575
2576  /* if it already exists then go with it.  This lets users override */
2577  if (owl_global_get_filter(&g, filtname)) {
2578    return filtname;
2579  }
2580
2581  /* create the new-internal filter */
2582  f=owl_malloc(sizeof(owl_filter));
2583
2584  esctype = owl_text_quote(type, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2585
2586  argbuff = owl_sprintf("type ^%s$", esctype);
2587
2588  owl_filter_init_fromstring(f, filtname, argbuff);
2589
2590  /* add it to the global list */
2591  owl_global_add_filter(&g, f);
2592
2593  /* free stuff */
2594  owl_free(argbuff);
2595  owl_free(esctype);
2596
2597  return filtname;
2598}
2599
2600/* If flag is 1, marks for deletion.  If flag is 0,
2601 * unmarks for deletion. */
2602void owl_function_delete_curview_msgs(int flag)
2603{
2604  owl_view *v;
2605  int i, j;
2606
2607  v=owl_global_get_current_view(&g);
2608  j=owl_view_get_size(v);
2609  for (i=0; i<j; i++) {
2610    if (flag == 1) {
2611      owl_message_mark_delete(owl_view_get_element(v, i));
2612    } else if (flag == 0) {
2613      owl_message_unmark_delete(owl_view_get_element(v, i));
2614    }
2615  }
2616
2617  owl_function_makemsg("%i messages marked for %sdeletion", j, flag?"":"un");
2618
2619  owl_mainwin_redisplay(owl_global_get_mainwin(&g)); 
2620}
2621
2622/* Create a filter based on the current message.  Returns the name of
2623 * a filter or null.  The caller must free this name.
2624 *
2625 * if the curmsg is a personal zephyr return a filter name
2626 *    to the zephyr converstaion with that user.
2627 * If the curmsg is a zephyr class message, instance foo, recip *,
2628 *    return a filter name to the class, inst.
2629 * If the curmsg is a zephyr class message and type==0 then
2630 *    return a filter name for just the class.
2631 * If the curmsg is a zephyr class message and type==1 then
2632 *    return a filter name for the class and instance.
2633 * If the curmsg is a personal AIM message returna  filter
2634 *    name to the AIM conversation with that user
2635 */
2636char *owl_function_smartfilter(int type)
2637{
2638  owl_view *v;
2639  owl_message *m;
2640  char *zperson, *filtname=NULL;
2641  char *argv[1];
2642 
2643  v=owl_global_get_current_view(&g);
2644  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2645
2646  if (!m || owl_view_get_size(v)==0) {
2647    owl_function_error("No message selected\n");
2648    return(NULL);
2649  }
2650
2651  /* very simple handling of admin messages for now */
2652  if (owl_message_is_type_admin(m)) {
2653    return(owl_function_typefilt("admin"));
2654  }
2655
2656  /* very simple handling of loopback messages for now */
2657  if (owl_message_is_type_loopback(m)) {
2658    return(owl_function_typefilt("loopback"));
2659  }
2660
2661  /* aim messages */
2662  if (owl_message_is_type_aim(m)) {
2663    if (owl_message_is_direction_in(m)) {
2664      filtname=owl_function_aimuserfilt(owl_message_get_sender(m));
2665    } else if (owl_message_is_direction_out(m)) {
2666      filtname=owl_function_aimuserfilt(owl_message_get_recipient(m));
2667    }
2668    return(filtname);
2669  }
2670
2671  /* narrow personal and login messages to the sender or recip as appropriate */
2672  if (owl_message_is_type_zephyr(m)) {
2673    if (owl_message_is_personal(m) || owl_message_is_loginout(m)) {
2674      if (owl_message_is_direction_in(m)) {
2675        zperson=short_zuser(owl_message_get_sender(m));
2676      } else {
2677        zperson=short_zuser(owl_message_get_recipient(m));
2678      }
2679      filtname=owl_function_zuserfilt(zperson);
2680      owl_free(zperson);
2681      return(filtname);
2682    }
2683
2684    /* narrow class MESSAGE, instance foo, recip * messages to class, inst */
2685    if (!strcasecmp(owl_message_get_class(m), "message")) {
2686      filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2687      return(filtname);
2688    }
2689
2690    /* otherwise narrow to the class */
2691    if (type==0) {
2692      filtname=owl_function_classinstfilt(owl_message_get_class(m), NULL);
2693    } else if (type==1) {
2694      filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2695    }
2696    return(filtname);
2697  }
2698
2699  /* pass it off to perl */
2700  if(type) {
2701    argv[0] = "-i";
2702  };
2703  return owl_perlconfig_message_call_method(m, "smartfilter", type ? 1 : 0, argv);
2704}
2705
2706void owl_function_smartzpunt(int type)
2707{
2708  /* Starts a zpunt command based on the current class,instance pair.
2709   * If type=0, uses just class.  If type=1, uses instance as well. */
2710  owl_view *v;
2711  owl_message *m;
2712  char *cmd, *cmdprefix, *mclass, *minst;
2713 
2714  v=owl_global_get_current_view(&g);
2715  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2716
2717  if (!m || owl_view_get_size(v)==0) {
2718    owl_function_error("No message selected\n");
2719    return;
2720  }
2721
2722  /* for now we skip admin messages. */
2723  if (owl_message_is_type_admin(m)
2724      || owl_message_is_loginout(m)
2725      || !owl_message_is_type_zephyr(m)) {
2726    owl_function_error("smartzpunt doesn't support this message type.");
2727    return;
2728  }
2729
2730  mclass = owl_message_get_class(m);
2731  minst = owl_message_get_instance(m);
2732  if (!mclass || !*mclass || *mclass==' '
2733      || (!strcasecmp(mclass, "message") && !strcasecmp(minst, "personal"))
2734      || (type && (!minst || !*minst|| *minst==' '))) {
2735    owl_function_error("smartzpunt can't safely do this for <%s,%s>",
2736                         mclass, minst);
2737  } else {
2738    cmdprefix = "start-command zpunt ";
2739    cmd = owl_malloc(strlen(cmdprefix)+strlen(mclass)+strlen(minst)+10);
2740    strcpy(cmd, cmdprefix);
2741    strcat(cmd, owl_getquoting(mclass));
2742    strcat(cmd, mclass);
2743    strcat(cmd, owl_getquoting(mclass));
2744    if (type) {
2745      strcat(cmd, " ");
2746      strcat(cmd, owl_getquoting(minst));
2747      strcat(cmd, minst);
2748      strcat(cmd, owl_getquoting(minst));
2749    } else {
2750      strcat(cmd, " *");
2751    }
2752    owl_function_command(cmd);
2753    owl_free(cmd);
2754  }
2755}
2756
2757/* Set the color of the current view's filter to
2758 * be 'color'
2759 */
2760void owl_function_color_current_filter(char *fgcolor, char *bgcolor)
2761{
2762  char *name;
2763
2764  name=owl_view_get_filtname(owl_global_get_current_view(&g));
2765  owl_function_color_filter(name, fgcolor, bgcolor);
2766}
2767
2768/* Set the color of the filter 'filter' to be 'color'.  If the color
2769 * name does not exist, return -1, if the filter does not exist or is
2770 * the "all" filter, return -2.  Return 0 on success
2771 */
2772int owl_function_color_filter(char *filtname, char *fgcolor, char *bgcolor)
2773{
2774  owl_filter *f;
2775
2776  f=owl_global_get_filter(&g, filtname);
2777  if (!f) {
2778    owl_function_error("Unknown filter");
2779    return(-2);
2780  }
2781
2782  /* don't touch the all filter */
2783  if (!strcmp(filtname, "all")) {
2784    owl_function_error("You may not change the 'all' filter.");
2785    return(-2);
2786  }
2787
2788  if (owl_util_string_to_color(fgcolor)==OWL_COLOR_INVALID) {
2789    owl_function_error("No color named '%s' avilable.", fgcolor);
2790    return(-1);
2791  }
2792
2793
2794  if (bgcolor != NULL) {
2795    if (owl_util_string_to_color(bgcolor)==OWL_COLOR_INVALID) {
2796      owl_function_error("No color named '%s' avilable.", bgcolor);
2797      return(-1);
2798    }
2799    owl_filter_set_bgcolor(f, owl_util_string_to_color(bgcolor));
2800  }
2801  owl_filter_set_fgcolor(f, owl_util_string_to_color(fgcolor));
2802 
2803  owl_global_set_needrefresh(&g);
2804  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2805  return(0);
2806}
2807
2808void owl_function_show_colors()
2809{
2810  owl_fmtext fm;
2811  int i; 
2812 
2813  owl_fmtext_init_null(&fm);
2814  owl_fmtext_append_normal(&fm, "default: ");
2815  owl_fmtext_append_normal_color(&fm, "default\n", OWL_COLOR_DEFAULT, OWL_COLOR_DEFAULT);
2816
2817  owl_fmtext_append_normal(&fm,"red:      ");
2818  owl_fmtext_append_normal_color(&fm, "red\n", OWL_COLOR_RED, OWL_COLOR_DEFAULT);
2819
2820  owl_fmtext_append_normal(&fm,"green:    ");
2821  owl_fmtext_append_normal_color(&fm, "green\n", OWL_COLOR_GREEN, OWL_COLOR_DEFAULT);
2822
2823  owl_fmtext_append_normal(&fm,"yellow:   ");
2824  owl_fmtext_append_normal_color(&fm, "yellow\n", OWL_COLOR_YELLOW, OWL_COLOR_DEFAULT);
2825
2826  owl_fmtext_append_normal(&fm,"blue:     ");
2827  owl_fmtext_append_normal_color(&fm, "blue\n", OWL_COLOR_BLUE, OWL_COLOR_DEFAULT);
2828
2829  owl_fmtext_append_normal(&fm,"magenta:  ");
2830  owl_fmtext_append_normal_color(&fm, "magenta\n", OWL_COLOR_MAGENTA, OWL_COLOR_DEFAULT);
2831
2832  owl_fmtext_append_normal(&fm,"cyan:     ");
2833  owl_fmtext_append_normal_color(&fm, "cyan\n", OWL_COLOR_CYAN, OWL_COLOR_DEFAULT);
2834
2835  owl_fmtext_append_normal(&fm,"white:    ");
2836  owl_fmtext_append_normal_color(&fm, "white\n", OWL_COLOR_WHITE, OWL_COLOR_DEFAULT);
2837
2838  for(i = 8; i < COLORS; ++i) {
2839    char* str1 = owl_sprintf("%4i:     ",i);
2840    char* str2 = owl_sprintf("%i\n",i);
2841    owl_fmtext_append_normal(&fm,str1);
2842    owl_fmtext_append_normal_color(&fm, str2, i, OWL_COLOR_DEFAULT);
2843    owl_free(str1);
2844     owl_free(str2);
2845  }
2846 
2847  owl_function_popless_fmtext(&fm);
2848  owl_fmtext_free(&fm);
2849}
2850
2851/* add the given class, inst, recip to the punt list for filtering.
2852 *   if direction==0 then punt
2853 *   if direction==1 then unpunt
2854 */
2855void owl_function_zpunt(char *class, char *inst, char *recip, int direction)
2856{
2857  char *buff;
2858  char *quoted;
2859
2860  buff=owl_malloc(strlen(class)+strlen(inst)+strlen(recip)+100);
2861  strcpy(buff, "class");
2862  if (!strcmp(class, "*")) {
2863    strcat(buff, " .*");
2864  } else {
2865    quoted=owl_text_quote(class, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2866    owl_text_tr(quoted, ' ', '.');
2867    owl_text_tr(quoted, '\'', '.');
2868    owl_text_tr(quoted, '"', '.');
2869    sprintf(buff + strlen(buff), " ^(un)*%s(\\.d)*$", quoted);
2870    owl_free(quoted);
2871  }
2872  if (!strcmp(inst, "*")) {
2873    strcat(buff, " and instance .*");
2874  } else {
2875    quoted=owl_text_quote(inst, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2876    owl_text_tr(quoted, ' ', '.');
2877    owl_text_tr(quoted, '\'', '.');
2878    owl_text_tr(quoted, '"', '.');
2879    sprintf(buff + strlen(buff), " and instance ^(un)*%s(\\.d)*$", quoted);
2880    owl_free(quoted);
2881  }
2882  if (strcmp(recip, "*")) {
2883    quoted=owl_text_quote(recip, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2884    owl_text_tr(quoted, ' ', '.');
2885    owl_text_tr(quoted, '\'', '.');
2886    owl_text_tr(quoted, '"', '.');
2887    sprintf(buff + strlen(buff), " and recipient ^%s$", quoted);
2888    owl_free(quoted);
2889  }
2890
2891  owl_function_punt(buff, direction);
2892  owl_free(buff);
2893}
2894
2895void owl_function_punt(char *filter, int direction)
2896{
2897  owl_filter *f;
2898  owl_list *fl;
2899  int ret, i, j;
2900  fl=owl_global_get_puntlist(&g);
2901
2902  /* first, create the filter */
2903  f=malloc(sizeof(owl_filter));
2904
2905  owl_function_debugmsg("About to filter %s", filter);
2906  ret=owl_filter_init_fromstring(f, "punt-filter", filter);
2907  if (ret) {
2908    owl_function_error("Error creating filter for zpunt");
2909    owl_filter_free(f);
2910    return;
2911  }
2912
2913  /* Check for an identical filter */
2914  j=owl_list_get_size(fl);
2915  for (i=0; i<j; i++) {
2916    if (owl_filter_equiv(f, owl_list_get_element(fl, i))) {
2917      owl_function_debugmsg("found an equivalent punt filter");
2918      /* if we're punting, then just silently bow out on this duplicate */
2919      if (direction==0) {
2920        owl_filter_free(f);
2921        return;
2922      }
2923
2924      /* if we're unpunting, then remove this filter from the puntlist */
2925      if (direction==1) {
2926        owl_filter_free(owl_list_get_element(fl, i));
2927        owl_list_remove_element(fl, i);
2928        owl_filter_free(f);
2929        return;
2930      }
2931    }
2932  }
2933
2934  owl_function_debugmsg("punting");
2935  /* If we're punting, add the filter to the global punt list */
2936  if (direction==0) {
2937    owl_list_append_element(fl, f);
2938  }
2939}
2940
2941void owl_function_activate_keymap(char *keymap)
2942{
2943  if (!owl_keyhandler_activate(owl_global_get_keyhandler(&g), keymap)) {
2944    owl_function_error("Unable to activate keymap '%s'", keymap);
2945  }
2946}
2947
2948void owl_function_show_keymaps()
2949{
2950  owl_list l;
2951  owl_fmtext fm;
2952  owl_keymap *km;
2953  owl_keyhandler *kh;
2954  int i, numkm;
2955  char *kmname;
2956
2957  kh = owl_global_get_keyhandler(&g);
2958  owl_fmtext_init_null(&fm);
2959  owl_fmtext_append_bold(&fm, "Keymaps:   ");
2960  owl_fmtext_append_normal(&fm, "(use 'show keymap <name>' for details)\n");
2961  owl_keyhandler_get_keymap_names(kh, &l);
2962  owl_fmtext_append_list(&fm, &l, "\n", owl_function_keymap_summary);
2963  owl_fmtext_append_normal(&fm, "\n");
2964
2965  numkm = owl_list_get_size(&l);
2966  for (i=0; i<numkm; i++) {
2967    kmname = owl_list_get_element(&l, i);
2968    km = owl_keyhandler_get_keymap(kh, kmname);
2969    owl_fmtext_append_bold(&fm, "\n\n----------------------------------------------------------------------------------------------------\n\n");
2970    owl_keymap_get_details(km, &fm);   
2971  }
2972  owl_fmtext_append_normal(&fm, "\n");
2973 
2974  owl_function_popless_fmtext(&fm);
2975  owl_keyhandler_keymap_namelist_free(&l);
2976  owl_fmtext_free(&fm);
2977}
2978
2979char *owl_function_keymap_summary(char *name)
2980{
2981  owl_keymap *km
2982    = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
2983  if (km) return owl_keymap_summary(km);
2984  else return(NULL);
2985}
2986
2987/* TODO: implement for real */
2988void owl_function_show_keymap(char *name)
2989{
2990  owl_fmtext fm;
2991  owl_keymap *km;
2992
2993  owl_fmtext_init_null(&fm);
2994  km = owl_keyhandler_get_keymap(owl_global_get_keyhandler(&g), name);
2995  if (km) {
2996    owl_keymap_get_details(km, &fm);
2997  } else {
2998    owl_fmtext_append_normal(&fm, "No such keymap...\n");
2999  } 
3000  owl_function_popless_fmtext(&fm);
3001  owl_fmtext_free(&fm);
3002}
3003
3004void owl_function_help_for_command(char *cmdname)
3005{
3006  owl_fmtext fm;
3007
3008  owl_fmtext_init_null(&fm);
3009  owl_cmd_get_help(owl_global_get_cmddict(&g), cmdname, &fm);
3010  owl_function_popless_fmtext(&fm); 
3011  owl_fmtext_free(&fm);
3012}
3013
3014void owl_function_search_start(char *string, int direction)
3015{
3016  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
3017  owl_global_set_search_active(&g, string);
3018  owl_function_search_helper(0, direction);
3019}
3020
3021void owl_function_search_continue(int direction)
3022{
3023  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
3024  owl_function_search_helper(1, direction);
3025}
3026
3027void owl_function_search_helper(int mode, int direction)
3028{
3029  /* move to a message that contains the string.  If direction is
3030   * OWL_DIRECTION_DOWNWARDS then search fowards, if direction is
3031   * OWL_DIRECTION_UPWARDS then search backwards.
3032   *
3033   * If mode==0 then it will stay on the current message if it
3034   * contains the string.
3035   */
3036
3037  owl_view *v;
3038  int viewsize, i, curmsg, start;
3039  owl_message *m;
3040
3041  v=owl_global_get_current_view(&g);
3042  viewsize=owl_view_get_size(v);
3043  curmsg=owl_global_get_curmsg(&g);
3044 
3045  if (viewsize==0) {
3046    owl_function_error("No messages present");
3047    return;
3048  }
3049
3050  if (mode==0) {
3051    start=curmsg;
3052  } else if (direction==OWL_DIRECTION_DOWNWARDS) {
3053    start=curmsg+1;
3054  } else {
3055    start=curmsg-1;
3056  }
3057
3058  /* bounds check */
3059  if (start>=viewsize || start<0) {
3060    owl_function_error("No further matches found");
3061    return;
3062  }
3063
3064  for (i=start; i<viewsize && i>=0;) {
3065    m=owl_view_get_element(v, i);
3066    if (owl_message_search(m, owl_global_get_search_string(&g))) {
3067      owl_global_set_curmsg(&g, i);
3068      owl_function_calculate_topmsg(direction);
3069      owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3070      if (direction==OWL_DIRECTION_DOWNWARDS) {
3071        owl_global_set_direction_downwards(&g);
3072      } else {
3073        owl_global_set_direction_upwards(&g);
3074      }
3075      return;
3076    }
3077    if (direction==OWL_DIRECTION_DOWNWARDS) {
3078      i++;
3079    } else {
3080      i--;
3081    }
3082  }
3083  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3084  owl_function_error("No matches found");
3085}
3086
3087/* strips formatting from ztext and returns the unformatted text.
3088 * caller is responsible for freeing. */
3089char *owl_function_ztext_stylestrip(char *zt)
3090{
3091  owl_fmtext fm;
3092  char *plaintext;
3093
3094  owl_fmtext_init_null(&fm);
3095  owl_fmtext_append_ztext(&fm, zt);
3096  plaintext = owl_fmtext_print_plain(&fm);
3097  owl_fmtext_free(&fm);
3098  return(plaintext);
3099}
3100
3101/* Popup a buddylisting.  If filename is NULL use the default .anyone */
3102void owl_function_buddylist(int aim, int zephyr, char *filename)
3103{
3104  int i, j, x, idle;
3105  owl_fmtext fm;
3106  owl_buddylist *bl;
3107  owl_buddy *b;
3108  owl_list anyone;
3109  char *foo, *timestr;
3110#ifdef HAVE_LIBZEPHYR
3111  char *tmp, *user, *line;
3112  ZLocations_t location[200];
3113  int numlocs, ret;
3114#endif
3115
3116  owl_fmtext_init_null(&fm);
3117
3118  /* AIM first */
3119  if (aim && owl_global_is_aimloggedin(&g)) {
3120    bl=owl_global_get_buddylist(&g);
3121
3122    owl_fmtext_append_bold(&fm, "AIM users logged in:\n");
3123    /* we're assuming AIM for now */
3124    j=owl_buddylist_get_size(bl);
3125    for (i=0; i<j; i++) {
3126      b=owl_buddylist_get_buddy_n(bl, i);
3127      idle=owl_buddy_get_idle_time(b);
3128      if (idle!=0) {
3129        timestr=owl_util_minutes_to_timestr(idle);
3130      } else {
3131        timestr=owl_strdup("");
3132      }
3133      foo=owl_sprintf("  %-20.20s %-12.12s\n", owl_buddy_get_name(b), timestr);
3134      owl_fmtext_append_normal(&fm, foo);
3135      owl_free(timestr);
3136      owl_free(foo);
3137    }
3138  }
3139
3140#ifdef HAVE_LIBZEPHYR
3141  if (zephyr) {
3142    if(!owl_global_is_havezephyr(&g)) {
3143      owl_function_error("Zephyr currently not available.");
3144    } else {
3145      owl_fmtext_append_bold(&fm, "Zephyr users logged in:\n");
3146      owl_list_create(&anyone);
3147      ret=owl_zephyr_get_anyone_list(&anyone, filename);
3148      if (ret) {
3149        owl_fmtext_append_normal(&fm, "  Error opening file for zephyr buddies.\n");
3150      } else {
3151        j=owl_list_get_size(&anyone);
3152        for (i=0; i<j; i++) {
3153          user=owl_list_get_element(&anyone, i);
3154          ret=ZLocateUser(user, &numlocs, ZAUTH);
3155          if (ret!=ZERR_NONE) {
3156            owl_function_error("Error getting location for %s", user);
3157            continue;
3158          }
3159
3160          numlocs=200;
3161          ret=ZGetLocations(location, &numlocs);
3162          if (ret==0) {
3163            for (x=0; x<numlocs; x++) {
3164              line=owl_malloc(strlen(location[x].host)+strlen(location[x].time)+strlen(location[x].tty)+100);
3165              tmp=short_zuser(user);
3166              sprintf(line, "  %-10.10s %-24.24s %-12.12s  %20.20s\n",
3167                      tmp,
3168                      location[x].host,
3169                      location[x].tty,
3170                      location[x].time);
3171              owl_fmtext_append_normal(&fm, line);
3172              owl_free(tmp);
3173              owl_free(line);
3174            }
3175            if (numlocs>=200) {
3176              owl_fmtext_append_normal(&fm, "  Too many locations found for this user, truncating.\n");
3177            }
3178          }
3179        }
3180      }
3181      owl_list_free_all(&anyone, owl_free);
3182    } 
3183  }
3184#endif
3185
3186  if(aim && zephyr) {
3187      if(owl_perlconfig_is_function("BarnOwl::Hooks::_get_blist")) {
3188          char * perlblist = owl_perlconfig_execute("BarnOwl::Hooks::_get_blist()");
3189          if(perlblist) {
3190              owl_fmtext_append_ztext(&fm, perlblist);
3191              owl_free(perlblist);
3192          }
3193      }
3194  }
3195 
3196  owl_function_popless_fmtext(&fm);
3197  owl_fmtext_free(&fm);
3198}
3199
3200/* Dump messages in the current view to the file 'filename'. */
3201void owl_function_dump(char *filename) 
3202{
3203  int i, j, count;
3204  owl_message *m;
3205  owl_view *v;
3206  FILE *file;
3207  char *plaintext;
3208
3209  v=owl_global_get_current_view(&g);
3210
3211  /* in the future make it ask yes/no */
3212  /*
3213  ret=stat(filename, &sbuf);
3214  if (!ret) {
3215    ret=owl_function_askyesno("File exists, continue? [Y/n]");
3216    if (!ret) return;
3217  }
3218  */
3219
3220  file=fopen(filename, "w");
3221  if (!file) {
3222    owl_function_error("Error opening file");
3223    return;
3224  }
3225
3226  count=0;
3227  j=owl_view_get_size(v);
3228  for (i=0; i<j; i++) {
3229    m=owl_view_get_element(v, i);
3230    plaintext = owl_strip_format_chars(owl_message_get_text(m));
3231    if (plaintext) {
3232      fputs(plaintext, file);
3233      owl_free(plaintext);
3234    }
3235  }
3236  fclose(file);
3237  owl_function_makemsg("Messages dumped to %s", filename);
3238}
3239
3240void owl_function_do_newmsgproc(void)
3241{
3242  if (owl_global_get_newmsgproc(&g) && strcmp(owl_global_get_newmsgproc(&g), "")) {
3243    /* if there's a process out there, we need to check on it */
3244    if (owl_global_get_newmsgproc_pid(&g)) {
3245      owl_function_debugmsg("Checking on newmsgproc pid==%i", owl_global_get_newmsgproc_pid(&g));
3246      owl_function_debugmsg("Waitpid return is %i", waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG));
3247      waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG);
3248      if (waitpid(owl_global_get_newmsgproc_pid(&g), NULL, WNOHANG)==-1) {
3249        /* it exited */
3250        owl_global_set_newmsgproc_pid(&g, 0);
3251        owl_function_debugmsg("newmsgproc exited");
3252      } else {
3253        owl_function_debugmsg("newmsgproc did not exit");
3254      }
3255    }
3256   
3257    /* if it exited, fork & exec a new one */
3258    if (owl_global_get_newmsgproc_pid(&g)==0) {
3259      int i, myargc;
3260      i=fork();
3261      if (i) {
3262        /* parent set the child's pid */
3263        owl_global_set_newmsgproc_pid(&g, i);
3264        owl_function_debugmsg("I'm the parent and I started a new newmsgproc with pid %i", i);
3265      } else {
3266        /* child exec's the program */
3267        char **parsed;
3268        parsed=owl_parseline(owl_global_get_newmsgproc(&g), &myargc);
3269        if (myargc < 0) {
3270          owl_function_debugmsg("Could not parse newmsgproc '%s': unbalanced quotes?", owl_global_get_newmsgproc(&g));
3271        }
3272        if (myargc <= 0) {
3273          _exit(127);
3274        }
3275        parsed=owl_realloc(parsed, sizeof(*parsed) * (myargc+1));
3276        parsed[myargc] = NULL;
3277       
3278        owl_function_debugmsg("About to exec \"%s\" with %d arguments", parsed[0], myargc);
3279       
3280        execvp(parsed[0], parsed);
3281       
3282       
3283        /* was there an error exec'ing? */
3284        owl_function_debugmsg("Cannot run newmsgproc '%s': cannot exec '%s': %s", 
3285                              owl_global_get_newmsgproc(&g), parsed[0], strerror(errno));
3286        _exit(127);
3287      }
3288    }
3289  }
3290}
3291
3292/* print the xterm escape sequence to raise the window */
3293void owl_function_xterm_raise(void)
3294{
3295  printf("\033[5t");
3296}
3297
3298/* print the xterm escape sequence to deiconify the window */
3299void owl_function_xterm_deiconify(void)
3300{
3301  printf("\033[1t");
3302}
3303
3304/* Add the specified command to the startup file.  Eventually this
3305 * should be clever, and rewriting settings that will obviosly
3306 * override earlier settings with 'set' 'bindkey' and 'alias'
3307 * commands.  For now though we just remove any line that would
3308 * duplicate this one and then append this line to the end of
3309 * startupfile.
3310 */
3311void owl_function_addstartup(char *buff)
3312{
3313  FILE *file;
3314  char *filename;
3315
3316  filename=owl_global_get_startupfile(&g);
3317  file=fopen(filename, "a");
3318  if (!file) {
3319    owl_function_error("Error opening startupfile for new command");
3320    return;
3321  }
3322
3323  /* delete earlier copies */
3324  owl_util_file_deleteline(filename, buff, 1);
3325
3326  /* add this line */
3327  fprintf(file, "%s\n", buff);
3328
3329  fclose(file);
3330}
3331
3332/* Remove the specified command from the startup file. */
3333void owl_function_delstartup(char *buff)
3334{
3335  char *filename;
3336  filename=owl_global_get_startupfile(&g);
3337  owl_util_file_deleteline(filename, buff, 1);
3338}
3339
3340/* Execute owl commands from the given filename.  If the filename
3341 * is NULL, use the default owl startup commands file.
3342 */
3343void owl_function_source(char *filename)
3344{
3345  FILE *file;
3346  char buff[LINE];
3347  int fail_silent = 0;
3348
3349  if (!filename) {
3350    fail_silent = 1;
3351    filename=owl_global_get_startupfile(&g);
3352  }
3353  file=fopen(filename, "r");
3354  if (!file) {
3355    if (!fail_silent) {
3356      owl_function_error("Error opening file: %s", filename);
3357    }
3358    return;
3359  }
3360  while (fgets(buff, LINE, file)!=NULL) {
3361    if (buff[0] == '#') continue;
3362    buff[strlen(buff)-1]='\0';
3363    owl_function_command(buff);
3364  }
3365  fclose(file);
3366}
3367
3368void owl_function_change_style(owl_view *v, char *stylename)
3369{
3370  owl_style *s;
3371
3372  s=owl_global_get_style_by_name(&g, stylename);
3373  if (!s) {
3374    owl_function_error("No style named %s", stylename);
3375    return;
3376  }
3377  owl_view_set_style(v, s);
3378  owl_messagelist_invalidate_formats(owl_global_get_msglist(&g));
3379  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
3380  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3381}
3382
3383void owl_function_toggleoneline()
3384{
3385  owl_view *v;
3386  owl_style *s;
3387
3388  v=owl_global_get_current_view(&g);
3389  s=owl_view_get_style(v);
3390
3391  if (!owl_style_matches_name(s, "oneline")) {
3392    owl_function_change_style(v, "oneline");
3393  } else {
3394    owl_function_change_style(v, owl_global_get_default_style(&g));
3395  }
3396
3397  owl_messagelist_invalidate_formats(owl_global_get_msglist(&g));
3398  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
3399  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
3400}
3401
3402void owl_function_error(char *fmt, ...)
3403{
3404  va_list ap;
3405  char *buff, *buff2;
3406  char *nl;
3407  char *date;
3408  time_t now;
3409
3410  now=time(NULL);
3411  date=owl_strdup(ctime(&now));
3412  date[strlen(date)-1]='\0';
3413
3414  va_start(ap, fmt);
3415
3416  buff = g_strdup_vprintf(fmt, ap);
3417  buff2 = owl_sprintf("%s %s", date, buff);
3418  owl_function_debugmsg("ERROR: %s", buff);
3419  nl = strchr(buff, '\n');
3420  if(nl && *(nl + 1)) {
3421    /* Multiline error */
3422    owl_function_adminmsg("ERROR", buff);
3423  } else {
3424    owl_function_makemsg("[Error] %s", buff);
3425  }
3426  owl_errqueue_append_err(owl_global_get_errqueue(&g), buff2);
3427  va_end(ap);
3428  owl_free(date);
3429  owl_free(buff);
3430  owl_free(buff2);
3431}
3432
3433void owl_function_showerrs()
3434{
3435  owl_fmtext fm;
3436
3437  owl_fmtext_init_null(&fm);
3438  owl_fmtext_append_normal(&fm, "Errors:\n\n");
3439  owl_errqueue_to_fmtext(owl_global_get_errqueue(&g), &fm);
3440  owl_function_popless_fmtext(&fm);
3441}
3442
3443void owl_function_makemsg(char *fmt, ...)
3444{
3445  va_list ap;
3446  char buff[2048];
3447
3448  if (!owl_global_get_curs_msgwin(&g)) return;
3449
3450  va_start(ap, fmt);
3451  werase(owl_global_get_curs_msgwin(&g));
3452 
3453  vsnprintf(buff, 2048, fmt, ap);
3454  owl_function_debugmsg("makemsg: %s", buff);
3455  waddstr(owl_global_get_curs_msgwin(&g), buff); 
3456  wnoutrefresh(owl_global_get_curs_msgwin(&g));
3457  owl_global_set_needrefresh(&g);
3458  va_end(ap);
3459}
3460
3461/* get locations for everyone in .anyone.  If 'notify' is '1' then
3462 * send a pseudo login or logout message for everyone not in sync with
3463 * the global zephyr buddy list.  The list is updated regardless of
3464 * the status of 'notify'.
3465 */
3466void owl_function_zephyr_buddy_check(int notify)
3467{
3468#ifdef HAVE_LIBZEPHYR
3469  int i, j;
3470  owl_list anyone;
3471  owl_message *m;
3472  owl_zbuddylist *zbl;
3473  char *user;
3474  ZLocations_t location[200];
3475  int numlocs, ret;
3476
3477  zbl=owl_global_get_zephyr_buddylist(&g);
3478
3479  owl_list_create(&anyone);
3480  ret=owl_zephyr_get_anyone_list(&anyone, NULL);
3481
3482  j=owl_list_get_size(&anyone);
3483  for (i=0; i<j; i++) {
3484    user=owl_list_get_element(&anyone, i);
3485    ret=ZLocateUser(user, &numlocs, ZAUTH);
3486    if (ret!=ZERR_NONE) {
3487      owl_function_error("Error getting location for %s", user);
3488      continue;
3489    }
3490    numlocs=200;
3491    ret=ZGetLocations(location, &numlocs);
3492    if (ret==0) {
3493      if ((numlocs>0) && !owl_zbuddylist_contains_user(zbl, user)) {
3494        /* Send a PSEUDO LOGIN! */
3495        if (notify) {
3496          m=owl_malloc(sizeof(owl_message));
3497          owl_message_create_pseudo_zlogin(m, 0, user, location[0].host, location[0].time, location[0].tty);
3498          owl_global_messagequeue_addmsg(&g, m);
3499        }
3500        owl_zbuddylist_adduser(zbl, user);
3501        owl_function_debugmsg("owl_function_zephyr_buddy_check: login for %s ", user);
3502      } else if ((numlocs==0) && owl_zbuddylist_contains_user(zbl, user)) {
3503        /* I don't think this ever happens (if there are 0 locations we should get an error from
3504         * ZGetLocations)
3505         */
3506        owl_function_error("owl_function_zephyr_buddy_check: exceptional case logout for %s ",user);
3507      }
3508    } else if ((ret==ZERR_NOLOCATIONS) && owl_zbuddylist_contains_user(zbl, user)) {
3509      /* Send a PSEUDO LOGOUT! */
3510      if (notify) {
3511        m=owl_malloc(sizeof(owl_message));
3512        owl_message_create_pseudo_zlogin(m, 1, user, "", "", "");
3513        owl_global_messagequeue_addmsg(&g, m);
3514      }
3515      owl_zbuddylist_deluser(zbl, user);
3516      owl_function_debugmsg("owl_function_zephyr_buddy_check: logout for %s ",user);
3517    }
3518  }
3519
3520  owl_list_free_all(&anyone, owl_free);
3521#endif
3522}
3523
3524void owl_function_aimsearch_results(char *email, owl_list *namelist)
3525{
3526  owl_fmtext fm;
3527  int i, j;
3528
3529  owl_fmtext_init_null(&fm);
3530  owl_fmtext_append_normal(&fm, "AIM screennames associated with ");
3531  owl_fmtext_append_normal(&fm, email);
3532  owl_fmtext_append_normal(&fm, ":\n");
3533
3534  j=owl_list_get_size(namelist);
3535  for (i=0; i<j; i++) {
3536    owl_fmtext_append_normal(&fm, "  ");
3537    owl_fmtext_append_normal(&fm, owl_list_get_element(namelist, i));
3538    owl_fmtext_append_normal(&fm, "\n");
3539  }
3540
3541  owl_function_popless_fmtext(&fm);
3542  owl_fmtext_free(&fm);
3543}
3544
3545int owl_function_get_color_count()
3546{
3547     return COLORS;
3548}
Note: See TracBrowser for help on using the repository browser.