source: functions.c @ 5b75e8b

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