source: functions.c @ 6dc2d6b

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