source: functions.c @ 1aa2b1a

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