source: perlconfig.c @ 712caac

release-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 712caac was 712caac, checked in by Anders Kaseorg <andersk@mit.edu>, 15 years ago
Cast away const on strings passed to libzephyr (with new function zstr). libzephyr doesn’t use const anywhere, so we’re going to need to cast const char * to char * all the time when passing strings to it. We wrap this cast in a new inline function for better type safety. Signed-off-by: Anders Kaseorg <andersk@mit.edu>
  • Property mode set to 100644
File size: 13.7 KB
Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <errno.h>
7#define OWL_PERL
8#include "owl.h"
9
10extern XS(boot_BarnOwl);
11extern XS(boot_DynaLoader);
12/* extern XS(boot_DBI); */
13
14static void owl_perl_xs_init(pTHX)
15{
16  char *file = __FILE__;
17  dXSUB_SYS;
18  {
19    newXS("BarnOwl::bootstrap", boot_BarnOwl, file);
20    newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
21  }
22}
23
24SV *owl_perlconfig_message2hashref(owl_message *m)
25{
26  HV *h, *stash;
27  SV *hr;
28  char *ptr, *blessas, *type;
29  int i, j;
30  owl_pair *pair;
31  owl_filter *wrap;
32
33  if (!m) return &PL_sv_undef;
34  wrap = owl_global_get_filter(&g, "wordwrap");
35  if(!wrap) {
36      owl_function_error("wrap filter is not defined");
37      return &PL_sv_undef;
38  }
39
40  h = newHV();
41
42#define MSG2H(h,field) (void)hv_store(h, #field, strlen(#field),        \
43                                      newSVpv(owl_message_get_##field(m),0), 0)
44
45  if (owl_message_is_type_zephyr(m)
46      && owl_message_is_direction_in(m)) {
47    /* Handle zephyr-specific fields... */
48    AV *av_zfields;
49
50    av_zfields = newAV();
51    j=owl_zephyr_get_num_fields(owl_message_get_notice(m));
52    for (i=0; i<j; i++) {
53      ptr=owl_zephyr_get_field_as_utf8(owl_message_get_notice(m), i+1);
54      av_push(av_zfields, newSVpvn(ptr, strlen(ptr)));
55      owl_free(ptr);
56    }
57    (void)hv_store(h, "fields", strlen("fields"), newRV_noinc((SV*)av_zfields), 0);
58
59    (void)hv_store(h, "auth", strlen("auth"), 
60                   newSVpv(owl_zephyr_get_authstr(owl_message_get_notice(m)),0),0);
61  }
62
63  j=owl_list_get_size(&(m->attributes));
64  for(i=0; i<j; i++) {
65    pair=owl_list_get_element(&(m->attributes), i);
66    (void)hv_store(h, owl_pair_get_key(pair), strlen(owl_pair_get_key(pair)),
67                   newSVpv(owl_pair_get_value(pair),0),0);
68  }
69 
70  MSG2H(h, type);
71  MSG2H(h, direction);
72  MSG2H(h, class);
73  MSG2H(h, instance);
74  MSG2H(h, sender);
75  MSG2H(h, realm);
76  MSG2H(h, recipient);
77  MSG2H(h, opcode);
78  MSG2H(h, hostname);
79  MSG2H(h, body);
80  MSG2H(h, login);
81  MSG2H(h, zsig);
82  MSG2H(h, zwriteline);
83  if (owl_message_get_header(m)) {
84    MSG2H(h, header); 
85  }
86  (void)hv_store(h, "time", strlen("time"), newSVpv(owl_message_get_timestr(m),0),0);
87  (void)hv_store(h, "unix_time", strlen("unix_time"), newSViv(m->time), 0);
88  (void)hv_store(h, "id", strlen("id"), newSViv(owl_message_get_id(m)),0);
89  (void)hv_store(h, "deleted", strlen("deleted"), newSViv(owl_message_is_delete(m)),0);
90  (void)hv_store(h, "private", strlen("private"), newSViv(owl_message_is_private(m)),0);
91  (void)hv_store(h, "should_wordwrap",
92                 strlen("should_wordwrap"), newSViv(
93                                                    owl_filter_message_match(wrap, m)),0);
94
95  type = owl_message_get_type(m);
96  if(!type || !*type) type = "generic";
97  type = owl_strdup(type);
98  type[0] = toupper(type[0]);
99  blessas = owl_sprintf("BarnOwl::Message::%s", type);
100
101  hr = newRV_noinc((SV*)h);
102  stash =  gv_stashpv(blessas,0);
103  if(!stash) {
104    owl_function_error("No such class: %s for message type %s", blessas, owl_message_get_type(m));
105    stash = gv_stashpv("BarnOwl::Message", 1);
106  }
107  hr = sv_bless(hr,stash);
108  owl_free(type);
109  owl_free(blessas);
110  return hr;
111}
112
113SV *owl_perlconfig_curmessage2hashref(void) /*noproto*/
114{
115  int curmsg;
116  owl_view *v;
117  v=owl_global_get_current_view(&g);
118  if (owl_view_get_size(v) < 1) {
119    return &PL_sv_undef;
120  }
121  curmsg=owl_global_get_curmsg(&g);
122  return owl_perlconfig_message2hashref(owl_view_get_element(v, curmsg));
123}
124
125/* XXX TODO: Messages should round-trip properly between
126   message2hashref and hashref2message. Currently we lose
127   zephyr-specific properties stored in the ZNotice_t
128
129   This has been somewhat addressed, but is still not lossless.
130 */
131owl_message * owl_perlconfig_hashref2message(SV *msg)
132{
133  owl_message * m;
134  HE * ent;
135  I32 count, len;
136  char *key,*val;
137  HV * hash;
138  struct tm tm;
139
140  hash = (HV*)SvRV(msg);
141
142  m = owl_malloc(sizeof(owl_message));
143  owl_message_init(m);
144
145  count = hv_iterinit(hash);
146  while((ent = hv_iternext(hash))) {
147    key = hv_iterkey(ent, &len);
148    val = SvPV_nolen(hv_iterval(hash, ent));
149    if(!strcmp(key, "type")) {
150      owl_message_set_type(m, val);
151    } else if(!strcmp(key, "direction")) {
152      owl_message_set_direction(m, owl_message_parse_direction(val));
153    } else if(!strcmp(key, "private")) {
154      SV * v = hv_iterval(hash, ent);
155      if(SvTRUE(v)) {
156        owl_message_set_isprivate(m);
157      }
158    } else if (!strcmp(key, "hostname")) {
159      owl_message_set_hostname(m, val);
160    } else if (!strcmp(key, "zwriteline")) {
161      owl_message_set_zwriteline(m, val);
162    } else if (!strcmp(key, "time")) {
163      m->timestr = owl_strdup(val);
164      strptime(val, "%a %b %d %T %Y", &tm);
165      m->time = mktime(&tm);
166    } else {
167      owl_message_set_attribute(m, key, val);
168    }
169  }
170  if(owl_message_is_type_admin(m)) {
171    if(!owl_message_get_attribute_value(m, "adminheader"))
172      owl_message_set_attribute(m, "adminheader", "");
173  }
174#ifdef HAVE_LIBZEPHYR
175  if (owl_message_is_type_zephyr(m)) {
176    ZNotice_t *n = &(m->notice);
177    n->z_kind = ACKED;
178    n->z_port = 0;
179    n->z_auth = ZAUTH_NO;
180    n->z_checked_auth = 0;
181    n->z_class = zstr(owl_message_get_class(m));
182    n->z_class_inst = zstr(owl_message_get_instance(m));
183    n->z_opcode = zstr(owl_message_get_opcode(m));
184    n->z_sender = zstr(owl_message_get_sender(m));
185    n->z_recipient = zstr(owl_message_get_recipient(m));
186    n->z_default_format = zstr("[zephyr created from perl]");
187    n->z_multinotice = zstr("[zephyr created from perl]");
188    n->z_num_other_fields = 0;
189    n->z_message = owl_sprintf("%s%c%s", owl_message_get_zsig(m), '\0', owl_message_get_body(m));
190    n->z_message_len = strlen(owl_message_get_zsig(m)) + strlen(owl_message_get_body(m)) + 1;
191  }
192#endif
193  return m;
194}
195
196/* Calls in a scalar context, passing it a hash reference.
197   If return value is non-null, caller must free. */
198char *owl_perlconfig_call_with_message(char *subname, owl_message *m)
199{
200  dSP ;
201  int count;
202  SV *msgref, *srv;
203  char *out;
204 
205  ENTER ;
206  SAVETMPS;
207 
208  PUSHMARK(SP) ;
209  msgref = owl_perlconfig_message2hashref(m);
210  XPUSHs(sv_2mortal(msgref));
211  PUTBACK ;
212 
213  count = call_pv(subname, G_SCALAR|G_EVAL|G_KEEPERR);
214 
215  SPAGAIN ;
216
217  if (SvTRUE(ERRSV)) {
218    owl_function_error("Perl Error: '%s'", SvPV_nolen(ERRSV));
219    /* and clear the error */
220    sv_setsv (ERRSV, &PL_sv_undef);
221  }
222
223  if (count != 1) {
224    fprintf(stderr, "bad perl!  no biscuit!  returned wrong count!\n");
225    abort();
226  }
227
228  srv = POPs;
229
230  if (srv) {
231    out = owl_strdup(SvPV_nolen(srv));
232  } else {
233    out = NULL;
234  }
235 
236  PUTBACK ;
237  FREETMPS ;
238  LEAVE ;
239
240  return out;
241}
242
243
244/* Calls a method on a perl object representing a message.
245   If the return value is non-null, the caller must free it.
246 */
247char * owl_perlconfig_message_call_method(owl_message *m, char *method, int argc, char ** argv)
248{
249  dSP;
250  unsigned int count, i;
251  SV *msgref, *srv;
252  char *out;
253
254  msgref = owl_perlconfig_message2hashref(m);
255
256  ENTER;
257  SAVETMPS;
258
259  PUSHMARK(SP);
260  XPUSHs(sv_2mortal(msgref));
261  for(i=0;i<argc;i++) {
262    XPUSHs(sv_2mortal(newSVpv(argv[i], 0)));
263  }
264  PUTBACK;
265
266  count = call_method(method, G_SCALAR|G_KEEPERR|G_EVAL);
267
268  SPAGAIN;
269
270  if(count != 1) {
271    fprintf(stderr, "perl returned wrong count %d\n", count);
272    abort();
273  }
274
275  if (SvTRUE(ERRSV)) {
276    owl_function_error("Error: '%s'", SvPV_nolen(ERRSV));
277    /* and clear the error */
278    sv_setsv (ERRSV, &PL_sv_undef);
279  }
280
281  srv = POPs;
282
283  if (srv) {
284    out = owl_strdup(SvPV_nolen(srv));
285  } else {
286    out = NULL;
287  }
288
289  PUTBACK;
290  FREETMPS;
291  LEAVE;
292
293  return out;
294}
295
296
297char *owl_perlconfig_initperl(char * file, int *Pargc, char ***Pargv, char *** Penv)
298{
299  int ret;
300  PerlInterpreter *p;
301  char *err;
302  char *args[4] = {"", "-e", "0;", NULL};
303  AV *inc;
304  char *path;
305
306  /* create and initialize interpreter */
307  PERL_SYS_INIT3(Pargc, Pargv, Penv);
308  p=perl_alloc();
309  owl_global_set_perlinterp(&g, p);
310  perl_construct(p);
311
312  owl_global_set_no_have_config(&g);
313
314  ret=perl_parse(p, owl_perl_xs_init, 2, args, NULL);
315  if (ret || SvTRUE(ERRSV)) {
316    err=owl_strdup(SvPV_nolen(ERRSV));
317    sv_setsv(ERRSV, &PL_sv_undef);     /* and clear the error */
318    return(err);
319  }
320
321  ret=perl_run(p);
322  if (ret || SvTRUE(ERRSV)) {
323    err=owl_strdup(SvPV_nolen(ERRSV));
324    sv_setsv(ERRSV, &PL_sv_undef);     /* and clear the error */
325    return(err);
326  }
327
328  owl_global_set_have_config(&g);
329
330  /* create legacy variables */
331  get_sv("BarnOwl::id", TRUE);
332  get_sv("BarnOwl::class", TRUE);
333  get_sv("BarnOwl::instance", TRUE);
334  get_sv("BarnOwl::recipient", TRUE);
335  get_sv("BarnOwl::sender", TRUE);
336  get_sv("BarnOwl::realm", TRUE);
337  get_sv("BarnOwl::opcode", TRUE);
338  get_sv("BarnOwl::zsig", TRUE);
339  get_sv("BarnOwl::msg", TRUE);
340  get_sv("BarnOwl::time", TRUE);
341  get_sv("BarnOwl::host", TRUE);
342  get_av("BarnOwl::fields", TRUE);
343
344  if(file) {
345    SV * cfg = get_sv("BarnOwl::configfile", TRUE);
346    sv_setpv(cfg, file);
347  }
348
349  /* Add the system lib path to @INC */
350  inc = get_av("INC", 0);
351  path = owl_sprintf("%s/lib", owl_get_datadir());
352  av_unshift(inc, 1);
353  av_store(inc, 0, newSVpv(path, 0));
354  owl_free(path);
355
356  eval_pv("use BarnOwl;", FALSE);
357
358  if (SvTRUE(ERRSV)) {
359    err=owl_strdup(SvPV_nolen(ERRSV));
360    sv_setsv (ERRSV, &PL_sv_undef);     /* and clear the error */
361    return(err);
362  }
363
364  /* check if we have the formatting function */
365  if (owl_perlconfig_is_function("BarnOwl::format_msg")) {
366    owl_global_set_config_format(&g, 1);
367  }
368
369  return(NULL);
370}
371
372/* returns whether or not a function exists */
373int owl_perlconfig_is_function(char *fn) {
374  if (get_cv(fn, FALSE)) return(1);
375  else return(0);
376}
377
378/* caller is responsible for freeing returned string */
379char *owl_perlconfig_execute(char *line)
380{
381  STRLEN len;
382  SV *response;
383  char *out, *preout;
384
385  if (!owl_global_have_config(&g)) return NULL;
386
387  ENTER;
388  SAVETMPS;
389  /* execute the subroutine */
390  response = eval_pv(line, FALSE);
391
392  if (SvTRUE(ERRSV)) {
393    owl_function_error("Perl Error: '%s'", SvPV_nolen(ERRSV));
394    sv_setsv (ERRSV, &PL_sv_undef);     /* and clear the error */
395  }
396
397  preout=SvPV(response, len);
398  if (len == 0 || preout[len - 1] != '\n')
399    out = owl_sprintf("%s\n", preout);
400  else
401    out = owl_strdup(preout);
402  FREETMPS;
403  LEAVE;
404
405  return(out);
406}
407
408void owl_perlconfig_getmsg(owl_message *m, char *subname)
409{
410  char *ptr = NULL;
411  if (owl_perlconfig_is_function("BarnOwl::Hooks::_receive_msg")) {
412    ptr = owl_perlconfig_call_with_message(subname?subname
413                                           :"BarnOwl::_receive_msg_legacy_wrap", m);
414  }
415  if (ptr) owl_free(ptr);
416}
417
418/* Called on all new messages; receivemsg is only called on incoming ones */
419void owl_perlconfig_newmsg(owl_message *m, char *subname)
420{
421  char *ptr = NULL;
422  if (owl_perlconfig_is_function("BarnOwl::Hooks::_new_msg")) {
423    ptr = owl_perlconfig_call_with_message(subname?subname
424                                           :"BarnOwl::Hooks::_new_msg", m);
425  }
426  if (ptr) owl_free(ptr);
427}
428
429void owl_perlconfig_new_command(char *name)
430{
431  dSP;
432
433  ENTER;
434  SAVETMPS;
435
436  PUSHMARK(SP);
437  XPUSHs(sv_2mortal(newSVpv(name, 0)));
438  PUTBACK;
439
440  call_pv("BarnOwl::Hooks::_new_command", G_SCALAR|G_VOID);
441
442  SPAGAIN;
443
444  if(SvTRUE(ERRSV)) {
445    owl_function_error("%s", SvPV_nolen(ERRSV));
446  }
447
448  FREETMPS;
449  LEAVE;
450}
451
452char *owl_perlconfig_perlcmd(owl_cmd *cmd, int argc, char **argv)
453{
454  int i, count;
455  char * ret = NULL;
456  SV *rv;
457  dSP;
458
459  ENTER;
460  SAVETMPS;
461
462  PUSHMARK(SP);
463  for(i=0;i<argc;i++) {
464    SV *tmp = newSVpv(argv[i], 0);
465    SvUTF8_on(tmp);
466    XPUSHs(sv_2mortal(tmp));
467  }
468  PUTBACK;
469
470  count = call_sv(cmd->cmd_perl, G_SCALAR|G_EVAL);
471
472  SPAGAIN;
473
474  if(SvTRUE(ERRSV)) {
475    owl_function_error("%s", SvPV_nolen(ERRSV));
476    (void)POPs;
477  } else {
478    if(count != 1)
479      croak("Perl command %s returned more than one value!", cmd->name);
480    rv = POPs;
481    if(SvTRUE(rv)) {
482      ret = owl_strdup(SvPV_nolen(rv));
483    }
484  }
485
486  FREETMPS;
487  LEAVE;
488
489  return ret;
490}
491
492void owl_perlconfig_cmd_free(owl_cmd *cmd)
493{
494  SvREFCNT_dec(cmd->cmd_perl);
495}
496
497void owl_perlconfig_dispatch_free(owl_dispatch *d)
498{
499  SvREFCNT_dec(d->data);
500  owl_free(d);
501}
502
503void owl_perlconfig_edit_callback(owl_editwin *e)
504{
505  SV *cb = owl_editwin_get_cbdata(e);
506  SV *text;
507  dSP;
508
509  if(cb == NULL) {
510    owl_function_error("Perl callback is NULL!");
511  }
512  text = newSVpv(owl_editwin_get_text(e), 0);
513  SvUTF8_on(text);
514
515  ENTER;
516  SAVETMPS;
517
518  PUSHMARK(SP);
519  XPUSHs(sv_2mortal(text));
520  PUTBACK;
521 
522  call_sv(cb, G_DISCARD|G_KEEPERR|G_EVAL);
523
524  if(SvTRUE(ERRSV)) {
525    owl_function_error("%s", SvPV_nolen(ERRSV));
526  }
527
528  FREETMPS;
529  LEAVE;
530
531  SvREFCNT_dec(cb);
532  owl_editwin_set_cbdata(e, NULL);
533}
534
535void owl_perlconfig_mainloop()
536{
537  dSP;
538  if (!owl_perlconfig_is_function("BarnOwl::Hooks::_mainloop_hook"))
539    return;
540  PUSHMARK(SP) ;
541  call_pv("BarnOwl::Hooks::_mainloop_hook", G_DISCARD|G_EVAL);
542  if(SvTRUE(ERRSV)) {
543    owl_function_error("%s", SvPV_nolen(ERRSV));
544  }
545  return;
546}
547
548void owl_perlconfig_dispatch(owl_dispatch *d)
549{
550  SV *cb = d->data;
551  dSP;
552  if(cb == NULL) {
553    owl_function_error("Perl callback is NULL!");
554    return;
555  }
556
557  ENTER;
558  SAVETMPS;
559
560  PUSHMARK(SP);
561  PUTBACK;
562 
563  call_sv(cb, G_DISCARD|G_KEEPERR|G_EVAL);
564
565  if(SvTRUE(ERRSV)) {
566    owl_function_error("%s", SvPV_nolen(ERRSV));
567  }
568
569  FREETMPS;
570  LEAVE;
571}
572
573void owl_perlconfig_perl_timer(owl_timer *t, void *data)
574{
575  SV *obj = data;
576
577  if(!SvROK(obj)) {
578    return;
579  }
580
581  dSP;
582  ENTER;
583  SAVETMPS;
584
585  PUSHMARK(SP);
586  XPUSHs(obj);
587  PUTBACK;
588
589  call_method("do_callback", G_DISCARD|G_KEEPERR|G_EVAL);
590
591  SPAGAIN;
592
593  if (SvTRUE(ERRSV)) {
594    owl_function_error("Error in calback: '%s'", SvPV_nolen(ERRSV));
595    sv_setsv (ERRSV, &PL_sv_undef);
596  }
597
598  PUTBACK;
599  FREETMPS;
600  LEAVE;
601}
602
603void owl_perlconfig_perl_timer_destroy(owl_timer *t)
604{
605  if(SvOK((SV*)t->data)) {
606    SvREFCNT_dec((SV*)t->data);
607  }
608}
Note: See TracBrowser for help on using the repository browser.