source: functions.c @ d754b0a

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