source: functions.c @ 0337203

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