source: functions.c @ 3c455b4

barnowl_perlaimdebianrelease-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 3c455b4 was ce74deb, checked in by Nelson Elhage <nelhage@mit.edu>, 18 years ago
Improving the private/personal distinction by fixing owl_message_is_personal * ``private'' means to/or from an individual, not a chat/class/etc. * ``personal'' means ``matches the personal filter''
  • Property mode set to 100644
File size: 100.9 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=""
[4228f8b]126    "barnowl version " OWL_VERSION_STRING "\n"
[debb15d]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));
[c2c5c77]1442
1443  if (owl_popwin_is_active(owl_global_get_popwin(&g))) {
1444    owl_popwin_refresh(owl_global_get_popwin(&g));
1445  }
[7d4fbcd]1446 
1447  sepbar("");
1448  owl_function_makemsg("");
1449
1450  owl_global_set_needrefresh(&g);
1451}
1452
[d54838d]1453void owl_function_popless_text(char *text)
1454{
[7d4fbcd]1455  owl_popwin *pw;
1456  owl_viewwin *v;
1457
1458  pw=owl_global_get_popwin(&g);
1459  v=owl_global_get_viewwin(&g);
1460
1461  owl_popwin_up(pw);
1462  owl_viewwin_init_text(v, owl_popwin_get_curswin(pw),
1463                        owl_popwin_get_lines(pw), owl_popwin_get_cols(pw),
1464                        text);
1465  owl_popwin_refresh(pw);
1466  owl_viewwin_redisplay(v, 0);
1467  owl_global_set_needrefresh(&g);
1468}
1469
[d54838d]1470void owl_function_popless_fmtext(owl_fmtext *fm)
1471{
[7d4fbcd]1472  owl_popwin *pw;
1473  owl_viewwin *v;
1474
1475  pw=owl_global_get_popwin(&g);
1476  v=owl_global_get_viewwin(&g);
1477
1478  owl_popwin_up(pw);
1479  owl_viewwin_init_fmtext(v, owl_popwin_get_curswin(pw),
1480                   owl_popwin_get_lines(pw), owl_popwin_get_cols(pw),
1481                   fm);
1482  owl_popwin_refresh(pw);
1483  owl_viewwin_redisplay(v, 0);
1484  owl_global_set_needrefresh(&g);
[f17bff98]1485}
1486
1487void owl_function_popless_file(char *filename)
1488{
1489  owl_fmtext fm;
1490  FILE *file;
1491  char buff[1024];
1492
1493  file=fopen(filename, "r");
1494  if (!file) {
1495    owl_function_error("Could not open file: %s", filename);
1496    return;
1497  }
1498
1499  owl_fmtext_init_null(&fm);
1500  while (fgets(buff, 1024, file)) {
1501    owl_fmtext_append_normal(&fm, buff);
[72836b5]1502    /*    owl_fmtext_append_normal(&fm, "\n"); */
[f17bff98]1503  }
1504
1505  owl_function_popless_fmtext(&fm);
1506  owl_fmtext_free(&fm);
1507  fclose(file);
[7d4fbcd]1508}
1509
[d54838d]1510void owl_function_about()
1511{
[7d4fbcd]1512  char buff[5000];
1513
[4228f8b]1514  sprintf(buff, "This is barnowl version %s\n\n", OWL_VERSION_STRING);
1515  strcat(buff, "barnowl is a fork of the Owl zephyr client, written and\n");
1516  strcat(buff, "maintained by Alejandro Sedeno and Nelson Elhage at the\n");
1517  strcat(buff, "Massachusetts Institute of Technology. \n");
1518  strcat(buff, "\n");
1519  strcat(buff, "Owl was written by James Kretchmar. The first version, 0.5, was\n");
[bde7714]1520  strcat(buff, "released in March 2002.\n");
[7d4fbcd]1521  strcat(buff, "\n");
1522  strcat(buff, "The name 'owl' was chosen in reference to the owls in the\n");
1523  strcat(buff, "Harry Potter novels, who are tasked with carrying messages\n");
[4228f8b]1524  strcat(buff, "between Witches and Wizards. The name 'barnowl' was chosen\n");
1525  strcat(buff, "because we feel our owls should live closer to our ponies.\n");
[7d4fbcd]1526  strcat(buff, "\n");
1527  strcat(buff, "Copyright 2002 Massachusetts Institute of Technology\n");
1528  strcat(buff, "\n");
1529  strcat(buff, "Permission to use, copy, modify, and distribute this\n");
1530  strcat(buff, "software and its documentation for any purpose and without\n");
1531  strcat(buff, "fee is hereby granted, provided that the above copyright\n");
1532  strcat(buff, "notice and this permission notice appear in all copies\n");
1533  strcat(buff, "and in supporting documentation.  No representation is\n");
1534  strcat(buff, "made about the suitability of this software for any\n");
1535  strcat(buff, "purpose.  It is provided \"as is\" without express\n");
1536  strcat(buff, "or implied warranty.\n");
1537  owl_function_popless_text(buff);
1538}
1539
[d54838d]1540void owl_function_info()
1541{
[7d4fbcd]1542  owl_message *m;
[5789230]1543  owl_fmtext fm, attrfm;
[09489b89]1544  char buff[10000];
[7d4fbcd]1545  owl_view *v;
[09489b89]1546#ifdef HAVE_LIBZEPHYR
1547  ZNotice_t *n;
1548#endif
[7d4fbcd]1549
[d0d65df]1550  owl_fmtext_init_null(&fm);
1551 
[7d4fbcd]1552  v=owl_global_get_current_view(&g);
[5eeea3b]1553  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
1554  if (!m || owl_view_get_size(v)==0) {
[ec6ff52]1555    owl_function_error("No message selected\n");
[7d4fbcd]1556    return;
1557  }
1558
[5789230]1559  owl_fmtext_append_bold(&fm, "General Information:\n");
1560  owl_fmtext_append_normal(&fm, "  Msg Id    : ");
[d0d65df]1561  sprintf(buff, "%i", owl_message_get_id(m));
1562  owl_fmtext_append_normal(&fm, buff);
1563  owl_fmtext_append_normal(&fm, "\n");
[df0d93a]1564
[5789230]1565  owl_fmtext_append_normal(&fm, "  Type      : ");
[37eab7f]1566  owl_fmtext_append_bold(&fm, owl_message_get_type(m));
[df0d93a]1567  owl_fmtext_append_normal(&fm, "\n");
1568
[4b464a4]1569  if (owl_message_is_direction_in(m)) {
[5789230]1570    owl_fmtext_append_normal(&fm, "  Direction : in\n");
[4b464a4]1571  } else if (owl_message_is_direction_out(m)) {
[5789230]1572    owl_fmtext_append_normal(&fm, "  Direction : out\n");
[4b464a4]1573  } else if (owl_message_is_direction_none(m)) {
[5789230]1574    owl_fmtext_append_normal(&fm, "  Direction : none\n");
[4b464a4]1575  } else {
[5789230]1576    owl_fmtext_append_normal(&fm, "  Direction : unknown\n");
[4b464a4]1577  }
[df0d93a]1578
[5789230]1579  owl_fmtext_append_normal(&fm, "  Time      : ");
[d0d65df]1580  owl_fmtext_append_normal(&fm, owl_message_get_timestr(m));
1581  owl_fmtext_append_normal(&fm, "\n");
[4b464a4]1582
[df0d93a]1583  if (!owl_message_is_type_admin(m)) {
[5789230]1584    owl_fmtext_append_normal(&fm, "  Sender    : ");
[df0d93a]1585    owl_fmtext_append_normal(&fm, owl_message_get_sender(m));
1586    owl_fmtext_append_normal(&fm, "\n");
1587   
[5789230]1588    owl_fmtext_append_normal(&fm, "  Recipient : ");
[df0d93a]1589    owl_fmtext_append_normal(&fm, owl_message_get_recipient(m));
1590    owl_fmtext_append_normal(&fm, "\n");
1591  }
1592   
[0ff8fb57]1593  if (owl_message_is_type_zephyr(m)) {
[5789230]1594    owl_fmtext_append_bold(&fm, "\nZephyr Specific Information:\n");
[0ff8fb57]1595   
[5789230]1596    owl_fmtext_append_normal(&fm, "  Class     : ");
[df0d93a]1597    owl_fmtext_append_normal(&fm, owl_message_get_class(m));
1598    owl_fmtext_append_normal(&fm, "\n");
[5789230]1599    owl_fmtext_append_normal(&fm, "  Instance  : ");
[df0d93a]1600    owl_fmtext_append_normal(&fm, owl_message_get_instance(m));
1601    owl_fmtext_append_normal(&fm, "\n");
[5789230]1602    owl_fmtext_append_normal(&fm, "  Opcode    : ");
[df0d93a]1603    owl_fmtext_append_normal(&fm, owl_message_get_opcode(m));
1604    owl_fmtext_append_normal(&fm, "\n");
1605   
[5789230]1606    owl_fmtext_append_normal(&fm, "  Time      : ");
[df0d93a]1607    owl_fmtext_append_normal(&fm, owl_message_get_timestr(m));
1608    owl_fmtext_append_normal(&fm, "\n");
[09489b89]1609#ifdef HAVE_LIBZEPHYR
[d0d65df]1610    if (owl_message_is_direction_in(m)) {
[09489b89]1611      char *ptr, tmpbuff[1024];
1612      int i, j, fields, len;
1613
[d0d65df]1614      n=owl_message_get_notice(m);
[df0d93a]1615
[5a95b69]1616      if (!owl_message_is_pseudo(m)) {
1617        owl_fmtext_append_normal(&fm, "  Kind      : ");
1618        if (n->z_kind==UNSAFE) {
1619          owl_fmtext_append_normal(&fm, "UNSAFE\n");
1620        } else if (n->z_kind==UNACKED) {
1621          owl_fmtext_append_normal(&fm, "UNACKED\n");
1622        } else if (n->z_kind==ACKED) {
1623          owl_fmtext_append_normal(&fm, "ACKED\n");
1624        } else if (n->z_kind==HMACK) {
1625          owl_fmtext_append_normal(&fm, "HMACK\n");
1626        } else if (n->z_kind==HMCTL) {
1627          owl_fmtext_append_normal(&fm, "HMCTL\n");
1628        } else if (n->z_kind==SERVACK) {
1629          owl_fmtext_append_normal(&fm, "SERVACK\n");
1630        } else if (n->z_kind==SERVNAK) {
1631          owl_fmtext_append_normal(&fm, "SERVNACK\n");
1632        } else if (n->z_kind==CLIENTACK) {
1633          owl_fmtext_append_normal(&fm, "CLIENTACK\n");
1634        } else if (n->z_kind==STAT) {
1635          owl_fmtext_append_normal(&fm, "STAT\n");
1636        } else {
1637          owl_fmtext_append_normal(&fm, "ILLEGAL VALUE\n");
1638        }
[d0d65df]1639      }
[5789230]1640      owl_fmtext_append_normal(&fm, "  Host      : ");
[d0d65df]1641      owl_fmtext_append_normal(&fm, owl_message_get_hostname(m));
[5a95b69]1642
1643      if (!owl_message_is_pseudo(m)) {
1644        owl_fmtext_append_normal(&fm, "\n");
[789462a]1645        sprintf(buff, "  Port      : %i\n", ntohs(n->z_port));
[5a95b69]1646        owl_fmtext_append_normal(&fm, buff);
1647
1648        owl_fmtext_append_normal(&fm,    "  Auth      : ");
1649        owl_fmtext_append_normal(&fm, owl_zephyr_get_authstr(n));
1650        owl_fmtext_append_normal(&fm, "\n");
[d0d65df]1651       
[5a95b69]1652        /* fix this */
1653        sprintf(buff, "  Checkd Ath: %i\n", n->z_checked_auth);
1654        sprintf(buff, "%s  Multi notc: %s\n", buff, n->z_multinotice);
1655        sprintf(buff, "%s  Num other : %i\n", buff, n->z_num_other_fields);
1656        sprintf(buff, "%s  Msg Len   : %i\n", buff, n->z_message_len);
1657        owl_fmtext_append_normal(&fm, buff);
[d0d65df]1658       
[5a95b69]1659        sprintf(buff, "  Fields    : %i\n", owl_zephyr_get_num_fields(n));
[d0d65df]1660        owl_fmtext_append_normal(&fm, buff);
[5a95b69]1661       
1662        fields=owl_zephyr_get_num_fields(n);
1663        for (i=0; i<fields; i++) {
1664          sprintf(buff, "  Field %i   : ", i+1);
1665         
[b0430a6]1666          ptr=owl_zephyr_get_field(n, i+1);
1667          len=strlen(ptr);
[5a95b69]1668          if (len<30) {
1669            strncpy(tmpbuff, ptr, len);
1670            tmpbuff[len]='\0';
1671          } else {
1672            strncpy(tmpbuff, ptr, 30);
1673            tmpbuff[30]='\0';
1674            strcat(tmpbuff, "...");
1675          }
[b0430a6]1676          owl_free(ptr);
[5a95b69]1677         
1678          for (j=0; j<strlen(tmpbuff); j++) {
1679            if (tmpbuff[j]=='\n') tmpbuff[j]='~';
1680            if (tmpbuff[j]=='\r') tmpbuff[j]='!';
1681          }
1682         
1683          strcat(buff, tmpbuff);
1684          strcat(buff, "\n");
1685          owl_fmtext_append_normal(&fm, buff);
1686        }
1687        owl_fmtext_append_normal(&fm, "  Default Fm:");
1688        owl_fmtext_append_normal(&fm, n->z_default_format);
[d0d65df]1689      }
[5a95b69]1690     
[7d4fbcd]1691    }
[09489b89]1692#endif   
[7d4fbcd]1693  }
[0ff8fb57]1694
1695  if (owl_message_is_type_aim(m)) {
[5789230]1696    owl_fmtext_append_bold(&fm, "\nAIM Specific Information:\n");
[0ff8fb57]1697  }
[5789230]1698
1699  owl_fmtext_append_bold(&fm, "\nOwl Message Attributes:\n");
1700  owl_message_attributes_tofmtext(m, &attrfm);
1701  owl_fmtext_append_fmtext(&fm, &attrfm);
[d0d65df]1702 
1703  owl_function_popless_fmtext(&fm);
[5789230]1704  owl_fmtext_free(&fm);
1705  owl_fmtext_free(&attrfm);
[7d4fbcd]1706}
1707
[5639bf2]1708/* print the current message in a popup window.
1709 * Use the 'default' style regardless of whatever
1710 * style the user may be using
1711 */
[d54838d]1712void owl_function_curmsg_to_popwin()
1713{
[7d4fbcd]1714  owl_popwin *pw;
1715  owl_view *v;
1716  owl_message *m;
[5639bf2]1717  owl_style *s;
1718  owl_fmtext fm;
[7d4fbcd]1719
[5639bf2]1720  v=owl_global_get_current_view(&g);
1721  s=owl_global_get_style_by_name(&g, "default");
[7d4fbcd]1722  pw=owl_global_get_popwin(&g);
1723
[5eeea3b]1724  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
1725
1726  if (!m || owl_view_get_size(v)==0) {
[ec6ff52]1727    owl_function_error("No current message");
[7d4fbcd]1728    return;
1729  }
1730
[5639bf2]1731  owl_fmtext_init_null(&fm);
1732  owl_style_get_formattext(s, &fm, m);
1733
1734  owl_function_popless_fmtext(&fm);
1735  owl_fmtext_free(&fm);
[7d4fbcd]1736}
1737
[d54838d]1738void owl_function_page_curmsg(int step)
1739{
[7d4fbcd]1740  /* scroll down or up within the current message IF the message is truncated */
1741
1742  int offset, curmsg, lines;
1743  owl_view *v;
1744  owl_message *m;
1745
1746  offset=owl_global_get_curmsg_vert_offset(&g);
1747  v=owl_global_get_current_view(&g);
1748  curmsg=owl_global_get_curmsg(&g);
1749  m=owl_view_get_element(v, curmsg);
[5eeea3b]1750  if (!m || owl_view_get_size(v)==0) return;
[7d4fbcd]1751  lines=owl_message_get_numlines(m);
1752
1753  if (offset==0) {
1754    /* Bail if the curmsg isn't the last one displayed */
1755    if (curmsg != owl_mainwin_get_last_msg(owl_global_get_mainwin(&g))) {
[f51bc78]1756      owl_function_makemsg("The entire message is already displayed");
[7d4fbcd]1757      return;
1758    }
1759   
1760    /* Bail if we're not truncated */
1761    if (!owl_mainwin_is_curmsg_truncated(owl_global_get_mainwin(&g))) {
[f51bc78]1762      owl_function_makemsg("The entire message is already displayed");
[7d4fbcd]1763      return;
1764    }
1765  }
1766 
1767 
1768  /* don't scroll past the last line */
1769  if (step>0) {
1770    if (offset+step > lines-1) {
1771      owl_global_set_curmsg_vert_offset(&g, lines-1);
1772    } else {
1773      owl_global_set_curmsg_vert_offset(&g, offset+step);
1774    }
1775  }
1776
1777  /* would we be before the beginning of the message? */
1778  if (step<0) {
1779    if (offset+step<0) {
1780      owl_global_set_curmsg_vert_offset(&g, 0);
1781    } else {
1782      owl_global_set_curmsg_vert_offset(&g, offset+step);
1783    }
1784  }
1785 
1786  /* redisplay */
1787  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1788  owl_global_set_needrefresh(&g);
1789}
1790
[d54838d]1791void owl_function_resize_typwin(int newsize)
1792{
[7d4fbcd]1793  owl_global_set_typwin_lines(&g, newsize);
1794  owl_function_resize();
1795}
1796
[d54838d]1797void owl_function_typwin_grow()
1798{
[7d4fbcd]1799  int i;
1800
1801  i=owl_global_get_typwin_lines(&g);
1802  owl_function_resize_typwin(i+1);
1803}
1804
[d54838d]1805void owl_function_typwin_shrink()
1806{
[7d4fbcd]1807  int i;
1808
1809  i=owl_global_get_typwin_lines(&g);
1810  if (i>2) {
1811    owl_function_resize_typwin(i-1);
1812  }
1813}
1814
[d54838d]1815void owl_function_mainwin_pagedown()
1816{
[7d4fbcd]1817  int i;
1818
1819  i=owl_mainwin_get_last_msg(owl_global_get_mainwin(&g));
1820  if (i<0) return;
[f2e36b5]1821  if (owl_mainwin_is_last_msg_truncated(owl_global_get_mainwin(&g))
1822      && (owl_global_get_curmsg(&g) < i)
1823      && (i>0)) {
1824    i--;
1825  }
[7d4fbcd]1826  owl_global_set_curmsg(&g, i);
1827  owl_function_nextmsg();
1828}
1829
[d54838d]1830void owl_function_mainwin_pageup()
1831{
[7d4fbcd]1832  owl_global_set_curmsg(&g, owl_global_get_topmsg(&g));
1833  owl_function_prevmsg();
1834}
1835
[d54838d]1836void owl_function_getsubs()
1837{
[09489b89]1838  char *buff;
[7d4fbcd]1839
[09489b89]1840  buff=owl_zephyr_getsubs();
[7d4fbcd]1841
[09489b89]1842  if (buff) {
1843    owl_function_popless_text(buff);
1844  } else {
1845    owl_function_popless_text("Error getting subscriptions");
[7d4fbcd]1846  }
[09489b89]1847           
[1c6c4d3]1848  owl_free(buff);
[7d4fbcd]1849}
1850
1851#define PABUFLEN 5000
[d54838d]1852void owl_function_printallvars()
1853{
[7d4fbcd]1854  char buff[PABUFLEN], *pos, *name;
1855  owl_list varnames;
1856  int i, numvarnames, rem;
1857
1858  pos = buff;
1859  pos += sprintf(pos, "%-20s = %s\n", "VARIABLE", "VALUE");
1860  pos += sprintf(pos, "%-20s   %s\n",  "--------", "-----");
1861  owl_variable_dict_get_names(owl_global_get_vardict(&g), &varnames);
1862  rem = (buff+PABUFLEN)-pos-1;
1863  numvarnames = owl_list_get_size(&varnames);
1864  for (i=0; i<numvarnames; i++) {
1865    name = owl_list_get_element(&varnames, i);
1866    if (name && name[0]!='_') {
1867      rem = (buff+PABUFLEN)-pos-1;   
1868      pos += snprintf(pos, rem, "\n%-20s = ", name);
1869      rem = (buff+PABUFLEN)-pos-1;   
1870      owl_variable_get_tostring(owl_global_get_vardict(&g), name, pos, rem);
1871      pos = buff+strlen(buff);
1872    }
1873  }
1874  rem = (buff+PABUFLEN)-pos-1;   
1875  snprintf(pos, rem, "\n");
1876  owl_variable_dict_namelist_free(&varnames);
1877 
1878  owl_function_popless_text(buff);
1879}
1880
[d54838d]1881void owl_function_show_variables()
1882{
[7d4fbcd]1883  owl_list varnames;
1884  owl_fmtext fm; 
1885  int i, numvarnames;
1886  char *varname;
1887
1888  owl_fmtext_init_null(&fm);
1889  owl_fmtext_append_bold(&fm, 
1890      "Variables: (use 'show variable <name>' for details)\n");
1891  owl_variable_dict_get_names(owl_global_get_vardict(&g), &varnames);
1892  numvarnames = owl_list_get_size(&varnames);
1893  for (i=0; i<numvarnames; i++) {
1894    varname = owl_list_get_element(&varnames, i);
1895    if (varname && varname[0]!='_') {
[aa2f33b3]1896      owl_variable_describe(owl_global_get_vardict(&g), varname, &fm);
[7d4fbcd]1897    }
1898  }
1899  owl_variable_dict_namelist_free(&varnames);
1900  owl_function_popless_fmtext(&fm);
1901  owl_fmtext_free(&fm);
1902}
1903
[d54838d]1904void owl_function_show_variable(char *name)
1905{
[7d4fbcd]1906  owl_fmtext fm; 
1907
1908  owl_fmtext_init_null(&fm);
1909  owl_variable_get_help(owl_global_get_vardict(&g), name, &fm);
1910  owl_function_popless_fmtext(&fm);
1911  owl_fmtext_free(&fm); 
1912}
1913
1914/* note: this applies to global message list, not to view.
1915 * If flag is 1, deletes.  If flag is 0, undeletes. */
[d54838d]1916void owl_function_delete_by_id(int id, int flag)
1917{
[7d4fbcd]1918  owl_messagelist *ml;
1919  owl_message *m;
1920  ml = owl_global_get_msglist(&g);
1921  m = owl_messagelist_get_by_id(ml, id);
1922  if (m) {
1923    if (flag == 1) {
1924      owl_message_mark_delete(m);
1925    } else if (flag == 0) {
1926      owl_message_unmark_delete(m);
1927    }
1928    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
1929    owl_global_set_needrefresh(&g);
1930  } else {
[ec6ff52]1931    owl_function_error("No message with id %d: unable to mark for (un)delete",id);
[7d4fbcd]1932  }
1933}
1934
[d54838d]1935void owl_function_delete_automsgs()
1936{
[7d4fbcd]1937  /* mark for deletion all messages in the current view that match the
1938   * 'trash' filter */
1939
1940  int i, j, count;
1941  owl_message *m;
1942  owl_view *v;
1943  owl_filter *f;
1944
1945  /* get the trash filter */
1946  f=owl_global_get_filter(&g, "trash");
1947  if (!f) {
[ec6ff52]1948    owl_function_error("No trash filter defined");
[7d4fbcd]1949    return;
1950  }
1951
1952  v=owl_global_get_current_view(&g);
1953
1954  count=0;
1955  j=owl_view_get_size(v);
1956  for (i=0; i<j; i++) {
1957    m=owl_view_get_element(v, i);
1958    if (owl_filter_message_match(f, m)) {
1959      count++;
1960      owl_message_mark_delete(m);
1961    }
1962  }
1963  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
[1c6c4d3]1964  owl_function_makemsg("%i messages marked for deletion", count);
[7d4fbcd]1965  owl_global_set_needrefresh(&g);
1966}
1967
[d54838d]1968void owl_function_status()
1969{
[7d4fbcd]1970  char buff[5000];
1971  time_t start;
1972  int up, days, hours, minutes;
[a352335c]1973  owl_fmtext fm;
1974
1975  owl_fmtext_init_null(&fm);
[7d4fbcd]1976
1977  start=owl_global_get_starttime(&g);
1978
[d9b0b972]1979  owl_fmtext_append_normal(&fm, "General Information:\n");
1980
1981  owl_fmtext_append_normal(&fm, "  Version: ");
[a352335c]1982  owl_fmtext_append_normal(&fm, OWL_VERSION_STRING);
1983  owl_fmtext_append_normal(&fm, "\n");
1984
[d9b0b972]1985  owl_fmtext_append_normal(&fm, "  Startup Arugments: ");
[a352335c]1986  owl_fmtext_append_normal(&fm, owl_global_get_startupargs(&g));
1987  owl_fmtext_append_normal(&fm, "\n");
[b6a7367]1988
1989  owl_fmtext_append_normal(&fm, "  Current Directory: ");
1990  (void) getcwd(buff, MAXPATHLEN);
1991  owl_fmtext_append_normal(&fm, buff);
1992  owl_fmtext_append_normal(&fm, "\n");
1993
[d9b0b972]1994  sprintf(buff, "  Startup Time: %s", ctime(&start));
[a352335c]1995  owl_fmtext_append_normal(&fm, buff);
[7d4fbcd]1996
1997  up=owl_global_get_runtime(&g);
1998  days=up/86400;
1999  up-=days*86400;
2000  hours=up/3600;
2001  up-=hours*3600;
2002  minutes=up/60;
2003  up-=minutes*60;
[d9b0b972]2004  sprintf(buff, "  Run Time: %i days %2.2i:%2.2i:%2.2i\n", days, hours, minutes, up);
[a352335c]2005  owl_fmtext_append_normal(&fm, buff);
[7d4fbcd]2006
[d9b0b972]2007  owl_fmtext_append_normal(&fm, "\nProtocol Options:\n");
2008  owl_fmtext_append_normal(&fm, "  Zephyr included    : ");
2009  if (owl_global_is_havezephyr(&g)) {
2010    owl_fmtext_append_normal(&fm, "yes\n");
[7d4fbcd]2011  } else {
[d9b0b972]2012    owl_fmtext_append_normal(&fm, "no\n");
[7d4fbcd]2013  }
[d9b0b972]2014  owl_fmtext_append_normal(&fm, "  AIM included       : yes\n");
2015  owl_fmtext_append_normal(&fm, "  Loopback included  : yes\n");
2016
[8262340]2017
[d9b0b972]2018  owl_fmtext_append_normal(&fm, "\nBuild Options:\n");
2019  owl_fmtext_append_normal(&fm, "  Stderr redirection : ");
2020#if OWL_STDERR_REDIR
2021  owl_fmtext_append_normal(&fm, "yes\n");
2022#else
2023  owl_fmtext_append_normal(&fm, "no\n");
2024#endif
2025 
2026
2027  owl_fmtext_append_normal(&fm, "\nMemory Usage:\n");
2028  owl_fmtext_append_normal(&fm, "  Not currently available.\n");
[a352335c]2029  /*
[8262340]2030  sprintf(buff, "%sMemory Malloced: %i\n", buff, owl_global_get_malloced(&g));
2031  sprintf(buff, "%sMemory Freed: %i\n", buff, owl_global_get_freed(&g));
2032  sprintf(buff, "%sMemory In Use: %i\n", buff, owl_global_get_meminuse(&g));
[a352335c]2033  */
[8262340]2034
[d9b0b972]2035  owl_fmtext_append_normal(&fm, "\nAIM Status:\n");
2036  owl_fmtext_append_normal(&fm, "  Logged in: ");
[a352335c]2037  if (owl_global_is_aimloggedin(&g)) {
2038    owl_fmtext_append_normal(&fm, owl_global_get_aim_screenname(&g));
2039    owl_fmtext_append_normal(&fm, "\n");
2040  } else {
[d9b0b972]2041    owl_fmtext_append_normal(&fm, "(not logged in)\n");
[a352335c]2042  }
[d9b0b972]2043
2044  owl_fmtext_append_normal(&fm, "  Processing events: ");
[a352335c]2045  if (owl_global_is_doaimevents(&g)) {
[d9b0b972]2046    owl_fmtext_append_normal(&fm, "yes\n");
[a352335c]2047  } else {
[d9b0b972]2048    owl_fmtext_append_normal(&fm, "no\n");
[a352335c]2049  }
2050
2051  owl_function_popless_fmtext(&fm);
2052  owl_fmtext_free(&fm);
[7d4fbcd]2053}
2054
[d54838d]2055void owl_function_show_term()
2056{
[7d4fbcd]2057  owl_fmtext fm;
2058  char buff[LINE];
2059
2060  owl_fmtext_init_null(&fm);
2061  sprintf(buff, "Terminal Lines: %i\nTerminal Columns: %i\n",
2062          owl_global_get_lines(&g),
2063          owl_global_get_cols(&g));
2064  owl_fmtext_append_normal(&fm, buff);
2065
2066  if (owl_global_get_hascolors(&g)) {
2067    owl_fmtext_append_normal(&fm, "Color: Yes\n");
2068    sprintf(buff, "Number of color pairs: %i\n", owl_global_get_colorpairs(&g));
2069    owl_fmtext_append_normal(&fm, buff);
2070    sprintf(buff, "Can change colors: %s\n", can_change_color() ? "yes" : "no");
2071    owl_fmtext_append_normal(&fm, buff);
2072  } else {
2073    owl_fmtext_append_normal(&fm, "Color: No\n");
2074  }
2075
2076  owl_function_popless_fmtext(&fm);
2077  owl_fmtext_free(&fm);
2078}
2079
[e7cc1c3]2080/* if type = 0 then normal reply.
2081 * if type = 1 then it's a reply to sender
2082 * if enter = 0 then allow the command to be edited
2083 * if enter = 1 then don't wait for editing
2084 */
[d54838d]2085void owl_function_reply(int type, int enter)
2086{
[e6449bc]2087  char *buff=NULL, *oldbuff;
[7d4fbcd]2088  owl_message *m;
2089  owl_filter *f;
2090 
2091  if (owl_view_get_size(owl_global_get_current_view(&g))==0) {
[ec6ff52]2092    owl_function_error("No message selected");
[7d4fbcd]2093  } else {
[e50cd56]2094    char *class, *inst, *to, *cc=NULL;
[7d4fbcd]2095   
2096    m=owl_view_get_element(owl_global_get_current_view(&g), owl_global_get_curmsg(&g));
[5eeea3b]2097    if (!m) {
[ec6ff52]2098      owl_function_error("No message selected");
[5eeea3b]2099      return;
2100    }
2101
[7d4fbcd]2102    /* first check if we catch the reply-lockout filter */
2103    f=owl_global_get_filter(&g, "reply-lockout");
2104    if (f) {
2105      if (owl_filter_message_match(f, m)) {
[ec6ff52]2106        owl_function_error("Sorry, replies to this message have been disabled by the reply-lockout filter");
[7d4fbcd]2107        return;
2108      }
2109    }
[4b464a4]2110
[12c35df]2111    /* loopback */
2112    if (owl_message_is_type_loopback(m)) {
2113      owl_function_loopwrite_setup();
2114      return;
2115    }
2116
[d09e5a1]2117    /* zephyr */
2118    if (owl_message_is_type_zephyr(m)) {
[e7cc1c3]2119      /* if it's a zephyr we sent, send it out the same way again */
[d09e5a1]2120      if (owl_message_is_direction_out(m)) {
2121        owl_function_zwrite_setup(owl_message_get_zwriteline(m));
2122        owl_global_set_buffercommand(&g, owl_message_get_zwriteline(m));
2123        return;
2124      }
[e7cc1c3]2125
2126      /* Special case a personal reply to a webzephyr user on a class */
[1d3e925]2127      if ((type==1) && !strcasecmp(owl_message_get_opcode(m), OWL_WEBZEPHYR_OPCODE)) {
2128        class=OWL_WEBZEPHYR_CLASS;
[e7cc1c3]2129        inst=owl_message_get_sender(m);
2130        to=OWL_WEBZEPHYR_PRINCIPAL;
[1d3e925]2131      } else if (!strcasecmp(owl_message_get_class(m), OWL_WEBZEPHYR_CLASS) && owl_message_is_loginout(m)) {
[f562355]2132        /* Special case LOGIN/LOGOUT notifications on class "webzephyr" */
[1d3e925]2133        class=OWL_WEBZEPHYR_CLASS;
[e7cc1c3]2134        inst=owl_message_get_instance(m);
2135        to=OWL_WEBZEPHYR_PRINCIPAL;
[f562355]2136      } else if (owl_message_is_loginout(m)) {
2137        /* Normal LOGIN/LOGOUT messages */
[7d4fbcd]2138        class="MESSAGE";
2139        inst="PERSONAL";
2140        to=owl_message_get_sender(m);
2141      } else if (type==1) {
[f562355]2142        /* Personal reply */
[7d4fbcd]2143        class="MESSAGE";
2144        inst="PERSONAL";
2145        to=owl_message_get_sender(m);
2146      } else {
[f562355]2147        /* General reply */
[7d4fbcd]2148        class=owl_message_get_class(m);
2149        inst=owl_message_get_instance(m);
2150        to=owl_message_get_recipient(m);
[e50cd56]2151        cc=owl_message_get_cc(m);
[7d4fbcd]2152        if (!strcmp(to, "") || !strcmp(to, "*")) {
2153          to="";
2154        } else if (to[0]=='@') {
2155          /* leave it, to get the realm */
2156        } else {
2157          to=owl_message_get_sender(m);
2158        }
2159      }
[d09e5a1]2160       
[7d4fbcd]2161      /* create the command line */
[9ceee9d]2162      if (!strcasecmp(owl_message_get_opcode(m), "CRYPT")) {
2163        buff=owl_strdup("zcrypt");
2164      } else {
2165        buff = owl_strdup("zwrite");
2166      }
[7d4fbcd]2167      if (strcasecmp(class, "message")) {
[e50cd56]2168        buff = owl_sprintf("%s -c %s%s%s", oldbuff=buff, owl_getquoting(class), class, owl_getquoting(class));
2169        owl_free(oldbuff);
[7d4fbcd]2170      }
2171      if (strcasecmp(inst, "personal")) {
[e50cd56]2172        buff = owl_sprintf("%s -i %s%s%s", oldbuff=buff, owl_getquoting(inst), inst, owl_getquoting(inst));
2173        owl_free(oldbuff);
[7d4fbcd]2174      }
2175      if (*to != '\0') {
[f9c43ae]2176        char *tmp, *oldtmp, *tmp2;
[601a9e0]2177        tmp=short_zuser(to);
[e50cd56]2178        if (cc) {
2179          tmp = owl_util_uniq(oldtmp=tmp, cc, "-");
2180          owl_free(oldtmp);
2181          buff = owl_sprintf("%s -C %s", oldbuff=buff, tmp);
2182          owl_free(oldbuff);
2183        } else {
[f9c43ae]2184          if (owl_global_is_smartstrip(&g)) {
2185            tmp2=tmp;
[e3d9c77]2186            tmp=owl_zephyr_smartstripped_user(tmp2);
[f9c43ae]2187            owl_free(tmp2);
2188          }
[e50cd56]2189          buff = owl_sprintf("%s %s", oldbuff=buff, tmp);
2190          owl_free(oldbuff);
2191        }
[7d4fbcd]2192        owl_free(tmp);
2193      }
[e50cd56]2194      if (cc) owl_free(cc);
[1b6b2f3]2195    } else if (owl_message_is_type_aim(m)) {
2196      /* aim */
[440ce01]2197      if (owl_message_is_direction_out(m)) {
2198        buff=owl_sprintf("aimwrite %s", owl_message_get_recipient(m));
2199      } else {
2200        buff=owl_sprintf("aimwrite %s", owl_message_get_sender(m));
2201      }
[1b6b2f3]2202    } else {
2203      char *cmd;
2204      if((type==0 && (cmd=owl_message_get_attribute_value(m, "replycmd")))
2205         || (type==1 && (cmd=owl_message_get_attribute_value(m, "replysendercmd")))) {
2206        buff = owl_strdup(cmd);
2207      }
[d09e5a1]2208    }
[1b6b2f3]2209
[e0540e4]2210    if(!buff) {
2211        owl_function_error("I don't know how to reply to that message.");
2212        return;
2213    }
2214   
[d09e5a1]2215    if (enter) {
2216      owl_history *hist = owl_global_get_cmd_history(&g);
2217      owl_history_store(hist, buff);
2218      owl_history_reset(hist);
2219      owl_function_command_norv(buff);
2220    } else {
2221      owl_function_start_command(buff);
[7d4fbcd]2222    }
[d09e5a1]2223    owl_free(buff);
[7d4fbcd]2224  }
2225}
2226
[d54838d]2227void owl_function_zlocate(int argc, char **argv, int auth)
2228{
[2527615]2229  owl_fmtext fm;
2230  char *ptr, buff[LINE];
2231  int i;
2232
2233  owl_fmtext_init_null(&fm);
[7d4fbcd]2234
[2527615]2235  for (i=0; i<argc; i++) {
2236    ptr=long_zuser(argv[i]);
2237    owl_zephyr_zlocate(ptr, buff, auth);
2238    owl_fmtext_append_normal(&fm, buff);
2239    owl_free(ptr);
[7d4fbcd]2240  }
2241
[2527615]2242  owl_function_popless_fmtext(&fm);
2243  owl_fmtext_free(&fm);
[7d4fbcd]2244}
2245
[d54838d]2246void owl_function_start_command(char *line)
2247{
[7d4fbcd]2248  int i, j;
2249  owl_editwin *tw;
2250
2251  tw=owl_global_get_typwin(&g);
2252  owl_global_set_typwin_active(&g);
[10b866d]2253  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, 
2254                        owl_global_get_cmd_history(&g));
2255
[7d4fbcd]2256  owl_editwin_set_locktext(tw, "command: ");
2257  owl_global_set_needrefresh(&g);
2258
2259  j=strlen(line);
2260  for (i=0; i<j; i++) {
2261    owl_editwin_process_char(tw, line[i]);
2262  }
2263  owl_editwin_redisplay(tw, 0);
[cf83b7a]2264
2265  owl_context_set_editline(owl_global_get_context(&g), tw);
2266  owl_function_activate_keymap("editline");
2267}
2268
2269void owl_function_start_question(char *line)
2270{
2271  owl_editwin *tw;
2272
2273  tw=owl_global_get_typwin(&g);
2274  owl_global_set_typwin_active(&g);
2275  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, owl_global_get_cmd_history(&g));
2276
2277  owl_editwin_set_locktext(tw, line);
2278  owl_global_set_needrefresh(&g);
2279
2280  owl_editwin_redisplay(tw, 0);
2281
2282  owl_context_set_editresponse(owl_global_get_context(&g), tw);
2283  owl_function_activate_keymap("editresponse");
[7d4fbcd]2284}
2285
[453bd70]2286void owl_function_start_password(char *line)
2287{
2288  owl_editwin *tw;
2289
2290  tw=owl_global_get_typwin(&g);
2291  owl_global_set_typwin_active(&g);
2292  owl_editwin_new_style(tw, OWL_EDITWIN_STYLE_ONELINE, owl_global_get_cmd_history(&g));
2293  owl_editwin_set_echochar(tw, '*');
2294
2295  owl_editwin_set_locktext(tw, line);
2296  owl_global_set_needrefresh(&g);
2297
2298  owl_editwin_redisplay(tw, 0);
2299
2300  owl_context_set_editresponse(owl_global_get_context(&g), tw);
2301  owl_function_activate_keymap("editresponse");
2302}
2303
[d54838d]2304char *owl_function_exec(int argc, char **argv, char *buff, int type)
2305{
[7d4fbcd]2306  /* if type == 1 display in a popup
2307   * if type == 2 display an admin messages
2308   * if type == 0 return output
2309   * else display in a popup
2310   */
2311  char *newbuff, *redirect = " 2>&1 < /dev/null";
2312  char *out, buff2[1024];
2313  int size;
2314  FILE *p;
2315
[2a2bb60]2316#if OWL_STDERR_REDIR
2317  redirect = " < /dev/null";
2318#endif
2319
[7d4fbcd]2320  if (argc<2) {
[ec6ff52]2321    owl_function_error("Wrong number of arguments to the exec command");
[7d4fbcd]2322    return NULL;
2323  }
2324
2325  buff = skiptokens(buff, 1);
2326  newbuff = owl_malloc(strlen(buff)+strlen(redirect)+1);
2327  strcpy(newbuff, buff);
2328  strcat(newbuff, redirect);
2329
[afbf668]2330  if (type == 1) {
2331    owl_popexec_new(newbuff);
[7d4fbcd]2332  } else {
[afbf668]2333    p=popen(newbuff, "r");
2334    out=owl_malloc(1024);
2335    size=1024;
2336    strcpy(out, "");
2337    while (fgets(buff2, 1024, p)!=NULL) {
2338      size+=1024;
2339      out=owl_realloc(out, size);
2340      strcat(out, buff2);
2341    }
2342    pclose(p);
2343   
2344    if (type==1) {
2345      owl_function_popless_text(out);
2346    } else if (type==0) {
2347      return out;
2348    } else if (type==2) {
2349      owl_function_adminmsg(buff, out);
2350    } else {
2351      owl_function_popless_text(out);
2352    }
2353    owl_free(out);
[7d4fbcd]2354  }
2355  return NULL;
2356}
2357
[d54838d]2358char *owl_function_perl(int argc, char **argv, char *buff, int type)
2359{
[7d4fbcd]2360  /* if type == 1 display in a popup
2361   * if type == 2 display an admin messages
2362   * if type == 0 return output
2363   * else display in a popup
2364   */
2365  char *perlout;
2366
2367  if (argc<2) {
[ec6ff52]2368    owl_function_error("Wrong number of arguments to perl command");
[7d4fbcd]2369    return NULL;
2370  }
2371
2372  /* consume first token (argv[0]) */
2373  buff = skiptokens(buff, 1);
2374
[f1e629d]2375  perlout = owl_perlconfig_execute(buff);
[7d4fbcd]2376  if (perlout) { 
2377    if (type==1) {
2378      owl_function_popless_text(perlout);
2379    } else if (type==2) {
2380      owl_function_adminmsg(buff, perlout);
2381    } else if (type==0) {
2382      return perlout;
2383    } else {
2384      owl_function_popless_text(perlout);
2385    }
2386    owl_free(perlout);
2387  }
2388  return NULL;
2389}
2390
[5e0b690]2391/* Change the filter associated with the current view.
2392 * This also figures out which message in the new filter
2393 * should have the pointer.
2394 */
[3895e23]2395void owl_function_change_currentview_filter(char *filtname)
[c3ab155]2396{
2397  owl_view *v;
2398  owl_filter *f;
2399  int curid=-1, newpos, curmsg;
2400  owl_message *curm=NULL;
2401
2402  v=owl_global_get_current_view(&g);
2403
2404  curmsg=owl_global_get_curmsg(&g);
2405  if (curmsg==-1) {
2406    owl_function_debugmsg("Hit the curmsg==-1 case in change_view");
2407  } else {
2408    curm=owl_view_get_element(v, curmsg);
2409    if (curm) {
2410      curid=owl_message_get_id(curm);
2411      owl_view_save_curmsgid(v, curid);
2412    }
2413  }
2414
2415  f=owl_global_get_filter(&g, filtname);
2416  if (!f) {
[ec6ff52]2417    owl_function_error("Unknown filter %s", filtname);
[c3ab155]2418    return;
2419  }
2420
2421  owl_view_new_filter(v, f);
2422
2423  /* Figure out what to set the current message to.
2424   * - If the view we're leaving has messages in it, go to the closest message
2425   *   to the last message pointed to in that view.
2426   * - If the view we're leaving is empty, try to restore the position
2427   *   from the last time we were in the new view.  */
2428  if (curm) {
2429    newpos = owl_view_get_nearest_to_msgid(v, curid);
2430  } else {
2431    newpos = owl_view_get_nearest_to_saved(v);
2432  }
2433
2434  owl_global_set_curmsg(&g, newpos);
2435  owl_function_calculate_topmsg(OWL_DIRECTION_DOWNWARDS);
2436  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2437  owl_global_set_direction_downwards(&g);
2438}
[7d4fbcd]2439
[5e0b690]2440/* Create a new filter, or replace an existing one
2441 * with a new definition.
2442 */
[d54838d]2443void owl_function_create_filter(int argc, char **argv)
2444{
[7d4fbcd]2445  owl_filter *f;
2446  owl_view *v;
2447  int ret, inuse=0;
2448
2449  if (argc < 2) {
[ec6ff52]2450    owl_function_error("Wrong number of arguments to filter command");
[7d4fbcd]2451    return;
2452  }
2453
[3895e23]2454  owl_function_debugmsg("owl_function_create_filter: starting to create filter named %s", argv[1]);
2455
[7d4fbcd]2456  v=owl_global_get_current_view(&g);
2457
2458  /* don't touch the all filter */
2459  if (!strcmp(argv[1], "all")) {
[ec6ff52]2460    owl_function_error("You may not change the 'all' filter.");
[7d4fbcd]2461    return;
2462  }
2463
2464  /* deal with the case of trying change the filter color */
2465  if (argc==4 && !strcmp(argv[2], "-c")) {
2466    f=owl_global_get_filter(&g, argv[1]);
2467    if (!f) {
[ec6ff52]2468      owl_function_error("The filter '%s' does not exist.", argv[1]);
[7d4fbcd]2469      return;
2470    }
[12c35df]2471    if (owl_util_string_to_color(argv[3])==-1) {
2472      owl_function_error("The color '%s' is not available.", argv[3]);
2473      return;
2474    }
[8fa9562]2475    owl_filter_set_fgcolor(f, owl_util_string_to_color(argv[3]));
2476    owl_global_set_needrefresh(&g);
2477    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2478    return;
2479  }
2480  if (argc==4 && !strcmp(argv[2], "-b")) {
2481    f=owl_global_get_filter(&g, argv[1]);
2482    if (!f) {
2483      owl_function_error("The filter '%s' does not exist.", argv[1]);
2484      return;
2485    }
2486    if (owl_util_string_to_color(argv[3])==-1) {
2487      owl_function_error("The color '%s' is not available.", argv[3]);
2488      return;
2489    }
2490    owl_filter_set_bgcolor(f, owl_util_string_to_color(argv[3]));
[7d4fbcd]2491    owl_global_set_needrefresh(&g);
2492    owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2493    return;
2494  }
2495
2496  /* create the filter and check for errors */
2497  f=owl_malloc(sizeof(owl_filter));
2498  ret=owl_filter_init(f, argv[1], argc-2, argv+2);
2499  if (ret==-1) {
2500    owl_free(f);
[40458b9]2501    owl_function_error("Invalid filter");
[7d4fbcd]2502    return;
2503  }
2504
2505  /* if the named filter is in use by the current view, remember it */
2506  if (!strcmp(owl_view_get_filtname(v), argv[1])) {
2507    inuse=1;
2508  }
2509
2510  /* if the named filter already exists, nuke it */
2511  if (owl_global_get_filter(&g, argv[1])) {
2512    owl_global_remove_filter(&g, argv[1]);
2513  }
2514
2515  /* add the filter */
2516  owl_global_add_filter(&g, f);
2517
2518  /* if it was in use by the current view then update */
2519  if (inuse) {
[3895e23]2520    owl_function_change_currentview_filter(argv[1]);
[7d4fbcd]2521  }
2522  owl_global_set_needrefresh(&g);
2523  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
2524}
2525
[3895e23]2526/* If 'filtername' does not start with 'not-' create a filter named
2527 * 'not-<filtername>' defined as "not filter <filtername>".  If the
2528 * filter 'not-<filtername>' already exists, do not overwrite it.  If
2529 * 'filtername' begins with 'not-' and a filter 'filtername' already
2530 * exists, then do nothing.  If the filter 'filtername' does not
2531 * exist, create it and define it as 'not filter <filtername>'
2532 *
2533 * Returns the name of the negated filter, which the caller must free.
2534 */
2535char *owl_function_create_negative_filter(char *filtername)
2536{
2537  char *newname;
2538  owl_filter *tmpfilt;
2539  char *argv[5];
2540
2541  owl_function_debugmsg("owl_function_create_negative_filter");
2542 
2543  if (!strncmp(filtername, "not-", 4)) {
2544    newname=owl_strdup(filtername+4);
2545  } else {
2546    newname=owl_sprintf("not-%s", filtername);
2547  }
2548
2549  tmpfilt=owl_global_get_filter(&g, newname);
2550  if (!tmpfilt) {
2551    argv[0]="filter"; /* anything is fine here */
2552    argv[1]=newname;
2553    argv[2]="not";
2554    argv[3]="filter";
2555    argv[4]=filtername;
2556    owl_function_create_filter(5, argv);
2557  }
2558
2559  owl_function_debugmsg("owl_function_create_negative_filter: returning with %s", newname);
2560  return(newname);
2561}
2562
[d54838d]2563void owl_function_show_filters()
2564{
[7d4fbcd]2565  owl_list *l;
2566  owl_filter *f;
2567  int i, j;
2568  owl_fmtext fm;
2569
2570  owl_fmtext_init_null(&fm);
2571
2572  l=owl_global_get_filterlist(&g);
2573  j=owl_list_get_size(l);
2574
2575  owl_fmtext_append_bold(&fm, "Filters:\n");
2576
2577  for (i=0; i<j; i++) {
2578    f=owl_list_get_element(l, i);
2579    owl_fmtext_append_normal(&fm, "   ");
2580    if (owl_global_get_hascolors(&g)) {
[8fa9562]2581      owl_fmtext_append_normal_color(&fm, owl_filter_get_name(f), owl_filter_get_fgcolor(f), owl_filter_get_bgcolor(f));
[7d4fbcd]2582    } else {
2583      owl_fmtext_append_normal(&fm, owl_filter_get_name(f));
2584    }
2585    owl_fmtext_append_normal(&fm, "\n");
2586  }
2587  owl_function_popless_fmtext(&fm);
2588  owl_fmtext_free(&fm);
2589}
2590
[d54838d]2591void owl_function_show_filter(char *name)
2592{
[7d4fbcd]2593  owl_filter *f;
2594  char buff[5000];
2595
2596  f=owl_global_get_filter(&g, name);
2597  if (!f) {
[ec6ff52]2598    owl_function_error("There is no filter named %s", name);
[7d4fbcd]2599    return;
2600  }
2601  owl_filter_print(f, buff);
2602  owl_function_popless_text(buff);
2603}
2604
[d54838d]2605void owl_function_show_zpunts()
2606{
[7d4fbcd]2607  owl_filter *f;
2608  owl_list *fl;
2609  char buff[5000];
2610  owl_fmtext fm;
2611  int i, j;
2612
2613  owl_fmtext_init_null(&fm);
2614
2615  fl=owl_global_get_puntlist(&g);
2616  j=owl_list_get_size(fl);
2617  owl_fmtext_append_bold(&fm, "Active zpunt filters:\n");
2618
2619  for (i=0; i<j; i++) {
2620    f=owl_list_get_element(fl, i);
2621    owl_filter_print(f, buff);
2622    owl_fmtext_append_normal(&fm, buff);
2623  }
2624  owl_function_popless_fmtext(&fm);
2625  owl_fmtext_free(&fm);
2626}
2627
[3abf28b]2628/* Create a filter for a class, instance if one doesn't exist.  If
2629 * instance is NULL then catch all messgaes in the class.  Returns the
2630 * name of the filter, which the caller must free.
2631 */
[7a20e4c]2632char *owl_function_classinstfilt(char *c, char *i) 
[d54838d]2633{
[7d4fbcd]2634  owl_list *fl;
2635  owl_filter *f;
2636  char *argbuff, *filtname;
[d54838d]2637  char *tmpclass, *tmpinstance = NULL;
[7a20e4c]2638  char *class, *instance = NULL;
[7d4fbcd]2639  int len;
2640
[7a20e4c]2641  class = owl_util_baseclass(c);
2642  if(i) {
2643    instance = owl_util_baseclass(i);
2644  }
2645
[7d4fbcd]2646  fl=owl_global_get_filterlist(&g);
2647
2648  /* name for the filter */
2649  len=strlen(class)+30;
2650  if (instance) len+=strlen(instance);
2651  filtname=owl_malloc(len);
2652  if (!instance) {
2653    sprintf(filtname, "class-%s", class);
2654  } else {
2655    sprintf(filtname, "class-%s-instance-%s", class, instance);
2656  }
[ed2412d]2657  /* downcase it */
[7d4fbcd]2658  downstr(filtname);
[4099cf8]2659  /* turn spaces, single quotes, and double quotes into dots */
[e3d9c77]2660  owl_text_tr(filtname, ' ', '.');
[4099cf8]2661  owl_text_tr(filtname, '\'', '.');
2662  owl_text_tr(filtname, '"', '.');
[ed2412d]2663 
[7d4fbcd]2664  /* if it already exists then go with it.  This lets users override */
2665  if (owl_global_get_filter(&g, filtname)) {
[ed2412d]2666    return(filtname);
[7d4fbcd]2667  }
2668
2669  /* create the new filter */
[995eb4b]2670  tmpclass=owl_text_quote(class, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
[12c35df]2671  owl_text_tr(tmpclass, ' ', '.');
[4099cf8]2672  owl_text_tr(tmpclass, '\'', '.');
2673  owl_text_tr(tmpclass, '"', '.');
[ed2412d]2674  if (instance) {
[995eb4b]2675    tmpinstance=owl_text_quote(instance, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
[12c35df]2676    owl_text_tr(tmpinstance, ' ', '.');
[4099cf8]2677    owl_text_tr(tmpinstance, '\'', '.');
2678    owl_text_tr(tmpinstance, '"', '.');
[ed2412d]2679  }
[29ebcea]2680  len = strlen(tmpclass);
2681  if(tmpinstance) len += strlen(tmpinstance);
2682  len += 60;
2683  argbuff = owl_malloc(len);
2684  sprintf(argbuff, "class ^(un)*%s(\\.d)*$", tmpclass);
[d54838d]2685  if (tmpinstance) {
[1aa2b1a]2686    sprintf(argbuff, "%s and ( instance ^%s(\\.d)*$ )", argbuff, tmpinstance);
[7d4fbcd]2687  }
[ed2412d]2688  owl_free(tmpclass);
[d54838d]2689  if (tmpinstance) owl_free(tmpinstance);
[7d4fbcd]2690
2691  f=owl_malloc(sizeof(owl_filter));
2692  owl_filter_init_fromstring(f, filtname, argbuff);
2693
2694  /* add it to the global list */
2695  owl_global_add_filter(&g, f);
2696
2697  owl_free(argbuff);
[be5aa09]2698  owl_free(class);
2699  if (instance) {
2700    owl_free(instance);
2701  }
[ed2412d]2702  return(filtname);
[7d4fbcd]2703}
2704
[3abf28b]2705/* Create a filter for personal zephyrs to or from the specified
2706 * zephyr user.  Includes login/logout notifications for the user.
2707 * The name of the filter will be 'user-<user>'.  If a filter already
2708 * exists with this name, no new filter will be created.  This allows
2709 * the configuration to override this function.  Returns the name of
2710 * the filter, which the caller must free.
2711 */
2712char *owl_function_zuserfilt(char *user)
[d54838d]2713{
[7d4fbcd]2714  owl_filter *f;
2715  char *argbuff, *longuser, *shortuser, *filtname;
2716
2717  /* stick the local realm on if it's not there */
[4b464a4]2718  longuser=long_zuser(user);
2719  shortuser=short_zuser(user);
[7d4fbcd]2720
2721  /* name for the filter */
2722  filtname=owl_malloc(strlen(shortuser)+20);
2723  sprintf(filtname, "user-%s", shortuser);
2724
2725  /* if it already exists then go with it.  This lets users override */
2726  if (owl_global_get_filter(&g, filtname)) {
[3abf28b]2727    return(owl_strdup(filtname));
[7d4fbcd]2728  }
2729
2730  /* create the new-internal filter */
2731  f=owl_malloc(sizeof(owl_filter));
2732
[4b464a4]2733  argbuff=owl_malloc(strlen(longuser)+1000);
2734  sprintf(argbuff, "( type ^zephyr$ and ( class ^message$ and instance ^personal$ and ");
2735  sprintf(argbuff, "%s ( ( direction ^in$ and sender ^%s$ ) or ( direction ^out$ and recipient ^%s$ ) ) )", argbuff, longuser, longuser);
2736  sprintf(argbuff, "%s or ( ( class ^login$ ) and ( sender ^%s$ ) ) )", argbuff, longuser);
[7d4fbcd]2737
2738  owl_filter_init_fromstring(f, filtname, argbuff);
2739
2740  /* add it to the global list */
2741  owl_global_add_filter(&g, f);
2742
2743  /* free stuff */
2744  owl_free(argbuff);
2745  owl_free(longuser);
2746  owl_free(shortuser);
[7360fab]2747
[ed2412d]2748  return(filtname);
[7d4fbcd]2749}
2750
[3abf28b]2751/* Create a filter for AIM IM messages to or from the specified
2752 * screenname.  The name of the filter will be 'aimuser-<user>'.  If a
2753 * filter already exists with this name, no new filter will be
2754 * created.  This allows the configuration to override this function.
2755 * Returns the name of the filter, which the caller must free.
2756 */
2757char *owl_function_aimuserfilt(char *user)
2758{
2759  owl_filter *f;
2760  char *argbuff, *filtname;
[af9b92e]2761  char *escuser;
[3abf28b]2762
2763  /* name for the filter */
2764  filtname=owl_malloc(strlen(user)+40);
2765  sprintf(filtname, "aimuser-%s", user);
2766
2767  /* if it already exists then go with it.  This lets users override */
2768  if (owl_global_get_filter(&g, filtname)) {
2769    return(owl_strdup(filtname));
2770  }
2771
2772  /* create the new-internal filter */
2773  f=owl_malloc(sizeof(owl_filter));
2774
[af9b92e]2775  escuser = owl_text_quote(user, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
2776
[3abf28b]2777  argbuff=owl_malloc(1000);
2778  sprintf(argbuff,
[af9b92e]2779          "( type ^aim$ and ( ( sender ^%s$ and recipient ^%s$ ) or ( sender ^%s$ and recipient ^%s$ ) ) )",
2780          escuser, owl_global_get_aim_screenname(&g), owl_global_get_aim_screenname(&g), escuser);
[3abf28b]2781
2782  owl_filter_init_fromstring(f, filtname, argbuff);
2783
2784  /* add it to the global list */
2785  owl_global_add_filter(&g, f);
2786
2787  /* free stuff */
2788  owl_free(argbuff);
[af9b92e]2789  owl_free(escuser);
[3abf28b]2790
2791  return(filtname);
2792}
2793
2794char *owl_function_typefilt(char *type)
[d54838d]2795{
[f73e519]2796  owl_filter *f;
2797  char *argbuff, *filtname;
2798
2799  /* name for the filter */
2800  filtname=owl_sprintf("type-%s", type);
2801
2802  /* if it already exists then go with it.  This lets users override */
2803  if (owl_global_get_filter(&g, filtname)) {
2804    return filtname;
2805  }
2806
2807  /* create the new-internal filter */
2808  f=owl_malloc(sizeof(owl_filter));
2809
2810  argbuff = owl_sprintf("type ^%s$", type);
2811
2812  owl_filter_init_fromstring(f, filtname, argbuff);
2813
2814  /* add it to the global list */
2815  owl_global_add_filter(&g, f);
2816
2817  /* free stuff */
2818  owl_free(argbuff);
2819
2820  return filtname;
2821}
2822
[7d4fbcd]2823/* If flag is 1, marks for deletion.  If flag is 0,
2824 * unmarks for deletion. */
[d54838d]2825void owl_function_delete_curview_msgs(int flag)
2826{
[7d4fbcd]2827  owl_view *v;
2828  int i, j;
2829
2830  v=owl_global_get_current_view(&g);
2831  j=owl_view_get_size(v);
2832  for (i=0; i<j; i++) {
2833    if (flag == 1) {
2834      owl_message_mark_delete(owl_view_get_element(v, i));
2835    } else if (flag == 0) {
2836      owl_message_unmark_delete(owl_view_get_element(v, i));
2837    }
2838  }
2839
2840  owl_function_makemsg("%i messages marked for %sdeletion", j, flag?"":"un");
2841
2842  owl_mainwin_redisplay(owl_global_get_mainwin(&g)); 
2843}
2844
[3abf28b]2845/* Create a filter based on the current message.  Returns the name of
2846 * a filter or null.  The caller must free this name.
2847 *
2848 * if the curmsg is a personal zephyr return a filter name
2849 *    to the zephyr converstaion with that user.
2850 * If the curmsg is a zephyr class message, instance foo, recip *,
2851 *    return a filter name to the class, inst.
2852 * If the curmsg is a zephyr class message and type==0 then
2853 *    return a filter name for just the class.
2854 * If the curmsg is a zephyr class message and type==1 then
2855 *    return a filter name for the class and instance.
2856 * If the curmsg is a personal AIM message returna  filter
2857 *    name to the AIM conversation with that user
2858 */
[d54838d]2859char *owl_function_smartfilter(int type)
2860{
[7d4fbcd]2861  owl_view *v;
2862  owl_message *m;
[4b464a4]2863  char *zperson, *filtname=NULL;
[7d4fbcd]2864 
2865  v=owl_global_get_current_view(&g);
2866  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2867
[5eeea3b]2868  if (!m || owl_view_get_size(v)==0) {
[ec6ff52]2869    owl_function_error("No message selected\n");
[4b464a4]2870    return(NULL);
[7d4fbcd]2871  }
2872
[f73e519]2873  /* very simple handling of admin messages for now */
[4b464a4]2874  if (owl_message_is_type_admin(m)) {
[3abf28b]2875    return(owl_function_typefilt("admin"));
2876  }
2877
[995eb4b]2878  /* very simple handling of loopback messages for now */
2879  if (owl_message_is_type_loopback(m)) {
2880    return(owl_function_typefilt("loopback"));
2881  }
2882
[3abf28b]2883  /* aim messages */
2884  if (owl_message_is_type_aim(m)) {
2885    if (owl_message_is_direction_in(m)) {
2886      filtname=owl_function_aimuserfilt(owl_message_get_sender(m));
2887    } else if (owl_message_is_direction_out(m)) {
2888      filtname=owl_function_aimuserfilt(owl_message_get_recipient(m));
2889    }
2890    return(filtname);
[7d4fbcd]2891  }
2892
[4b464a4]2893  /* narrow personal and login messages to the sender or recip as appropriate */
[25729b2]2894  if (owl_message_is_type_zephyr(m)) {
[ce74deb]2895    if (owl_message_is_private(m) || owl_message_is_loginout(m)) {
[4b464a4]2896      if (owl_message_is_direction_in(m)) {
[25729b2]2897        zperson=short_zuser(owl_message_get_sender(m));
[4b464a4]2898      } else {
[25729b2]2899        zperson=short_zuser(owl_message_get_recipient(m));
[4b464a4]2900      }
[3abf28b]2901      filtname=owl_function_zuserfilt(zperson);
[4b464a4]2902      owl_free(zperson);
2903      return(filtname);
[7d4fbcd]2904    }
2905
[25729b2]2906    /* narrow class MESSAGE, instance foo, recip * messages to class, inst */
[ce74deb]2907    if (!strcasecmp(owl_message_get_class(m), "message")) {
[25729b2]2908      filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2909      return(filtname);
2910    }
2911
2912    /* otherwise narrow to the class */
2913    if (type==0) {
2914      filtname=owl_function_classinstfilt(owl_message_get_class(m), NULL);
2915    } else if (type==1) {
2916      filtname=owl_function_classinstfilt(owl_message_get_class(m), owl_message_get_instance(m));
2917    }
[4b464a4]2918    return(filtname);
[7d4fbcd]2919  }
2920
[25729b2]2921  /* pass it off to perl */
2922  char *argv[1];
2923  if(type) {
2924    argv[0] = "-i";
2925  };
2926  return owl_perlconfig_message_call_method(m, "smartfilter", type ? 1 : 0, argv);
[7d4fbcd]2927}
2928
[d54838d]2929void owl_function_smartzpunt(int type)
2930{
[d36f2cb]2931  /* Starts a zpunt command based on the current class,instance pair.
2932   * If type=0, uses just class.  If type=1, uses instance as well. */
2933  owl_view *v;
2934  owl_message *m;
2935  char *cmd, *cmdprefix, *mclass, *minst;
2936 
2937  v=owl_global_get_current_view(&g);
2938  m=owl_view_get_element(v, owl_global_get_curmsg(&g));
2939
[5eeea3b]2940  if (!m || owl_view_get_size(v)==0) {
[ec6ff52]2941    owl_function_error("No message selected\n");
[d36f2cb]2942    return;
2943  }
2944
2945  /* for now we skip admin messages. */
[4b464a4]2946  if (owl_message_is_type_admin(m)
[5789230]2947      || owl_message_is_loginout(m)
[4b464a4]2948      || !owl_message_is_type_zephyr(m)) {
[ec6ff52]2949    owl_function_error("smartzpunt doesn't support this message type.");
[d36f2cb]2950    return;
2951  }
2952
[cee1f25]2953  mclass = owl_message_get_class(m);
2954  minst = owl_message_get_instance(m);
[d36f2cb]2955  if (!mclass || !*mclass || *mclass==' '
2956      || (!strcasecmp(mclass, "message") && !strcasecmp(minst, "personal"))
2957      || (type && (!minst || !*minst|| *minst==' '))) {
[ec6ff52]2958    owl_function_error("smartzpunt can't safely do this for <%s,%s>",
[d36f2cb]2959                         mclass, minst);
2960  } else {
2961    cmdprefix = "start-command zpunt ";
[cee1f25]2962    cmd = owl_malloc(strlen(cmdprefix)+strlen(mclass)+strlen(minst)+10);
[d36f2cb]2963    strcpy(cmd, cmdprefix);
[cee1f25]2964    strcat(cmd, owl_getquoting(mclass));
[d36f2cb]2965    strcat(cmd, mclass);
[cee1f25]2966    strcat(cmd, owl_getquoting(mclass));
[d36f2cb]2967    if (type) {
2968      strcat(cmd, " ");
[cee1f25]2969      strcat(cmd, owl_getquoting(minst));
[d36f2cb]2970      strcat(cmd, minst);
[cee1f25]2971      strcat(cmd, owl_getquoting(minst));
[d36f2cb]2972    } else {
2973      strcat(cmd, " *");
2974    }
2975    owl_function_command(cmd);
2976    owl_free(cmd);
2977  }
2978}
2979
[5e0b690]2980/* Set the color of the current view's filter to
2981 * be 'color'
2982 */
[8fa9562]2983void owl_function_color_current_filter(char *fgcolor, char *bgcolor)
[d54838d]2984{
[7d4fbcd]2985  char *name;
2986
2987  name=owl_view_get_filtname(owl_global_get_current_view(&g));
[8fa9562]2988  owl_function_color_filter(name, fgcolor, bgcolor);
[5e0b690]2989}
2990
2991/* Set the color of the filter 'filter' to be 'color'.  If the color
2992 * name does not exist, return -1, if the filter does not exist or is
2993 * the "all" filter, return -2.  Return 0 on success
2994 */
[8fa9562]2995int owl_function_color_filter(char *filtname, char *fgcolor, char *bgcolor)
[5e0b690]2996{
2997  owl_filter *f;
2998
2999  f=owl_global_get_filter(&g, filtname);
[7d4fbcd]3000  if (!f) {
[ec6ff52]3001    owl_function_error("Unknown filter");
[5e0b690]3002    return(-2);
[7d4fbcd]3003  }
3004
3005  /* don't touch the all filter */
[5e0b690]3006  if (!strcmp(filtname, "all")) {
[ec6ff52]3007    owl_function_error("You may not change the 'all' filter.");
[5e0b690]3008    return(-2);
[7d4fbcd]3009  }
3010
[8fa9562]3011  if (owl_util_string_to_color(fgcolor)==-1) {
3012    owl_function_error("No color named '%s' avilable.", fgcolor);
[5e0b690]3013    return(-1);
[12c35df]3014  }
[8fa9562]3015
3016
3017  if (bgcolor != NULL) {
3018    if (owl_util_string_to_color(bgcolor)==-1) {
3019      owl_function_error("No color named '%s' avilable.", bgcolor);
3020      return(-1);
3021    }
3022    owl_filter_set_bgcolor(f, owl_util_string_to_color(bgcolor));
3023  }
3024  owl_filter_set_fgcolor(f, owl_util_string_to_color(fgcolor));
3025 
[7d4fbcd]3026  owl_global_set_needrefresh(&g);
3027  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
[5e0b690]3028  return(0);
[7d4fbcd]3029}
3030
[d54838d]3031void owl_function_show_colors()
3032{
[7d4fbcd]3033  owl_fmtext fm;
[c2c5c77]3034  int i; 
3035 
[7d4fbcd]3036  owl_fmtext_init_null(&fm);
[ca9142e]3037  owl_fmtext_append_normal(&fm, "default: ");
[8fa9562]3038  owl_fmtext_append_normal_color(&fm, "default\n", OWL_COLOR_DEFAULT, OWL_COLOR_DEFAULT);
[ca9142e]3039
3040  owl_fmtext_append_normal(&fm,"red:      ");
[8fa9562]3041  owl_fmtext_append_normal_color(&fm, "red\n", OWL_COLOR_RED, OWL_COLOR_DEFAULT);
[ca9142e]3042
3043  owl_fmtext_append_normal(&fm,"green:    ");
[8fa9562]3044  owl_fmtext_append_normal_color(&fm, "green\n", OWL_COLOR_GREEN, OWL_COLOR_DEFAULT);
[ca9142e]3045
3046  owl_fmtext_append_normal(&fm,"yellow:   ");
[8fa9562]3047  owl_fmtext_append_normal_color(&fm, "yellow\n", OWL_COLOR_YELLOW, OWL_COLOR_DEFAULT);
[ca9142e]3048
3049  owl_fmtext_append_normal(&fm,"blue:     ");
[8fa9562]3050  owl_fmtext_append_normal_color(&fm, "blue\n", OWL_COLOR_BLUE, OWL_COLOR_DEFAULT);
[ca9142e]3051
3052  owl_fmtext_append_normal(&fm,"magenta:  ");
[8fa9562]3053  owl_fmtext_append_normal_color(&fm, "magenta\n", OWL_COLOR_MAGENTA, OWL_COLOR_DEFAULT);
[ca9142e]3054
3055  owl_fmtext_append_normal(&fm,"cyan:     ");
[8fa9562]3056  owl_fmtext_append_normal_color(&fm, "cyan\n", OWL_COLOR_CYAN, OWL_COLOR_DEFAULT);
[ca9142e]3057
3058  owl_fmtext_append_normal(&fm,"white:    ");
[8fa9562]3059  owl_fmtext_append_normal_color(&fm, "white\n", OWL_COLOR_WHITE, OWL_COLOR_DEFAULT);
[7d4fbcd]3060
[c2c5c77]3061  for(i = 8; i < COLORS; ++i) {
3062    char* str1 = owl_sprintf("%4i:     ",i);
3063    char* str2 = owl_sprintf("%i\n",i);
3064    owl_fmtext_append_normal(&fm,str1);
3065    owl_fmtext_append_normal_color(&fm, str2, i, OWL_COLOR_DEFAULT);
3066    owl_free(str1);
3067     owl_free(str2);
3068  }
3069 
[7d4fbcd]3070  owl_function_popless_fmtext(&fm);
3071  owl_fmtext_free(&fm);
3072}
3073
[5bb6c21]3074/* add the given class, inst, recip to the punt list for filtering.
3075 *   if direction==0 then punt
3076 *   if direction==1 then unpunt
3077 */
[d54838d]3078void owl_function_zpunt(char *class, char *inst, char *recip, int direction)
3079{
[7d4fbcd]3080  owl_filter *f;
3081  owl_list *fl;
3082  char *buff;
[bc08664]3083  char *quoted;
[7d4fbcd]3084  int ret, i, j;
3085
3086  fl=owl_global_get_puntlist(&g);
3087
3088  /* first, create the filter */
3089  f=malloc(sizeof(owl_filter));
3090  buff=malloc(strlen(class)+strlen(inst)+strlen(recip)+100);
[5bb6c21]3091  strcpy(buff, "class");
3092  if (!strcmp(class, "*")) {
3093    strcat(buff, " .*");
3094  } else {
[bc08664]3095    quoted=owl_text_quote(class, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
[cee1f25]3096    owl_text_tr(quoted, ' ', '.');
[4099cf8]3097    owl_text_tr(quoted, '\'', '.');
3098    owl_text_tr(quoted, '"', '.');
[1aa2b1a]3099    sprintf(buff, "%s ^(un)*%s(\\.d)*$", buff, quoted);
[bc08664]3100    owl_free(quoted);
[5bb6c21]3101  }
3102  if (!strcmp(inst, "*")) {
3103    strcat(buff, " and instance .*");
[7d4fbcd]3104  } else {
[bc08664]3105    quoted=owl_text_quote(inst, OWL_REGEX_QUOTECHARS, OWL_REGEX_QUOTEWITH);
[cee1f25]3106    owl_text_tr(quoted, ' ', '.');
[4099cf8]3107    owl_text_tr(quoted, '\'', '.');
3108    owl_text_tr(quoted, '"', '.');
[1aa2b1a]3109    sprintf(buff, "%s and instance ^(un)*%s(\\.d)*$", buff, quoted);
[bc08664]3110    owl_free(quoted);
[7d4fbcd]3111  }
[5bb6c21]3112  if (strcmp(recip, "*")