source: functions.c @ b363d83

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