source: perlconfig.c @ 65b2173

release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 65b2173 was 65b2173, checked in by Anders Kaseorg <andersk@mit.edu>, 9 years ago
Split up declarations for adding const qualifiers for char * and void *. 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 *preout;
384  char *out;
385
386  if (!owl_global_have_config(&g)) return NULL;
387
388  ENTER;
389  SAVETMPS;
390  /* execute the subroutine */
391  response = eval_pv(line, FALSE);
392
393  if (SvTRUE(ERRSV)) {
394    owl_function_error("Perl Error: '%s'", SvPV_nolen(ERRSV));
395    sv_setsv (ERRSV, &PL_sv_undef);     /* and clear the error */
396  }
397
398  preout=SvPV(response, len);
399  if (len == 0 || preout[len - 1] != '\n')
400    out = owl_sprintf("%s\n", preout);
401  else
402    out = owl_strdup(preout);
403  FREETMPS;
404  LEAVE;
405
406  return(out);
407}
408
409void owl_perlconfig_getmsg(owl_message *m, char *subname)
410{
411  char *ptr = NULL;
412  if (owl_perlconfig_is_function("BarnOwl::Hooks::_receive_msg")) {
413    ptr = owl_perlconfig_call_with_message(subname?subname
414                                           :"BarnOwl::_receive_msg_legacy_wrap", m);
415  }
416  if (ptr) owl_free(ptr);
417}
418
419/* Called on all new messages; receivemsg is only called on incoming ones */
420void owl_perlconfig_newmsg(owl_message *m, char *subname)
421{
422  char *ptr = NULL;
423  if (owl_perlconfig_is_function("BarnOwl::Hooks::_new_msg")) {
424    ptr = owl_perlconfig_call_with_message(subname?subname
425                                           :"BarnOwl::Hooks::_new_msg", m);
426  }
427  if (ptr) owl_free(ptr);
428}
429
430void owl_perlconfig_new_command(char *name)
431{
432  dSP;
433
434  ENTER;
435  SAVETMPS;
436
437  PUSHMARK(SP);
438  XPUSHs(sv_2mortal(newSVpv(name, 0)));
439  PUTBACK;
440
441  call_pv("BarnOwl::Hooks::_new_command", G_SCALAR|G_VOID);
442
443  SPAGAIN;
444
445  if(SvTRUE(ERRSV)) {
446    owl_function_error("%s", SvPV_nolen(ERRSV));
447  }
448
449  FREETMPS;
450  LEAVE;
451}
452
453char *owl_perlconfig_perlcmd(owl_cmd *cmd, int argc, char **argv)
454{
455  int i, count;
456  char * ret = NULL;
457  SV *rv;
458  dSP;
459
460  ENTER;
461  SAVETMPS;
462
463  PUSHMARK(SP);
464  for(i=0;i<argc;i++) {
465    SV *tmp = newSVpv(argv[i], 0);
466    SvUTF8_on(tmp);
467    XPUSHs(sv_2mortal(tmp));
468  }
469  PUTBACK;
470
471  count = call_sv(cmd->cmd_perl, G_SCALAR|G_EVAL);
472
473  SPAGAIN;
474
475  if(SvTRUE(ERRSV)) {
476    owl_function_error("%s", SvPV_nolen(ERRSV));
477    (void)POPs;
478  } else {
479    if(count != 1)
480      croak("Perl command %s returned more than one value!", cmd->name);
481    rv = POPs;
482    if(SvTRUE(rv)) {
483      ret = owl_strdup(SvPV_nolen(rv));
484    }
485  }
486
487  FREETMPS;
488  LEAVE;
489
490  return ret;
491}
492
493void owl_perlconfig_cmd_free(owl_cmd *cmd)
494{
495  SvREFCNT_dec(cmd->cmd_perl);
496}
497
498void owl_perlconfig_dispatch_free(owl_dispatch *d)
499{
500  SvREFCNT_dec(d->data);
501  owl_free(d);
502}
503
504void owl_perlconfig_edit_callback(owl_editwin *e)
505{
506  SV *cb = owl_editwin_get_cbdata(e);
507  SV *text;
508  dSP;
509
510  if(cb == NULL) {
511    owl_function_error("Perl callback is NULL!");
512  }
513  text = newSVpv(owl_editwin_get_text(e), 0);
514  SvUTF8_on(text);
515
516  ENTER;
517  SAVETMPS;
518
519  PUSHMARK(SP);
520  XPUSHs(sv_2mortal(text));
521  PUTBACK;
522 
523  call_sv(cb, G_DISCARD|G_KEEPERR|G_EVAL);
524
525  if(SvTRUE(ERRSV)) {
526    owl_function_error("%s", SvPV_nolen(ERRSV));
527  }
528
529  FREETMPS;
530  LEAVE;
531
532  SvREFCNT_dec(cb);
533  owl_editwin_set_cbdata(e, NULL);
534}
535
536void owl_perlconfig_mainloop()
537{
538  dSP;
539  if (!owl_perlconfig_is_function("BarnOwl::Hooks::_mainloop_hook"))
540    return;
541  PUSHMARK(SP) ;
542  call_pv("BarnOwl::Hooks::_mainloop_hook", G_DISCARD|G_EVAL);
543  if(SvTRUE(ERRSV)) {
544    owl_function_error("%s", SvPV_nolen(ERRSV));
545  }
546  return;
547}
548
549void owl_perlconfig_dispatch(owl_dispatch *d)
550{
551  SV *cb = d->data;
552  dSP;
553  if(cb == NULL) {
554    owl_function_error("Perl callback is NULL!");
555    return;
556  }
557
558  ENTER;
559  SAVETMPS;
560
561  PUSHMARK(SP);
562  PUTBACK;
563 
564  call_sv(cb, G_DISCARD|G_KEEPERR|G_EVAL);
565
566  if(SvTRUE(ERRSV)) {
567    owl_function_error("%s", SvPV_nolen(ERRSV));
568  }
569
570  FREETMPS;
571  LEAVE;
572}
573
574void owl_perlconfig_perl_timer(owl_timer *t, void *data)
575{
576  SV *obj = data;
577
578  if(!SvROK(obj)) {
579    return;
580  }
581
582  dSP;
583  ENTER;
584  SAVETMPS;
585
586  PUSHMARK(SP);
587  XPUSHs(obj);
588  PUTBACK;
589
590  call_method("do_callback", G_DISCARD|G_KEEPERR|G_EVAL);
591
592  SPAGAIN;
593
594  if (SvTRUE(ERRSV)) {
595    owl_function_error("Error in calback: '%s'", SvPV_nolen(ERRSV));
596    sv_setsv (ERRSV, &PL_sv_undef);
597  }
598
599  PUTBACK;
600  FREETMPS;
601  LEAVE;
602}
603
604void owl_perlconfig_perl_timer_destroy(owl_timer *t)
605{
606  if(SvOK((SV*)t->data)) {
607    SvREFCNT_dec((SV*)t->data);
608  }
609}
Note: See TracBrowser for help on using the repository browser.