source: functions.c @ 8ae2de9

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