source: functions.c @ db1af5f

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