source: functions.c @ 38cfdb5d

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