source: zephyr.c @ b848e30

release-1.10release-1.8release-1.9
Last change on this file since b848e30 was b848e30, checked in by David Benjamin <davidben@mit.edu>, 13 years ago
Fix the build on libzephyr-less machines Just don't compile the event source functions at all. There's no good reason to use them without libzephyr support. We should really move towards not building zephyr.c in that case anyway.
  • Property mode set to 100644
File size: 39.1 KB
RevLine 
[7d4fbcd]1#include <stdlib.h>
2#include <unistd.h>
3#include <sys/types.h>
4#include <sys/wait.h>
[4357be8]5#include <sys/stat.h>
[7d4fbcd]6#include <string.h>
7#include "owl.h"
8
[b848e30]9#ifdef HAVE_LIBZEPHYR
[959cb85]10static GSource *owl_zephyr_event_source_new(int fd);
11
12static gboolean owl_zephyr_event_prepare(GSource *source, int *timeout);
13static gboolean owl_zephyr_event_check(GSource *source);
14static gboolean owl_zephyr_event_dispatch(GSource *source, GSourceFunc callback, gpointer user_data);
15
[a5e7ed6]16static GList *deferred_subs = NULL;
[79d7d98]17
[a5e7ed6]18typedef struct _owl_sub_list {                            /* noproto */
19  ZSubscription_t *subs;
20  int nsubs;
21} owl_sub_list;
22
[c79a047]23Code_t ZResetAuthentication(void);
[959cb85]24
25static GSourceFuncs zephyr_event_funcs = {
26  owl_zephyr_event_prepare,
27  owl_zephyr_event_check,
28  owl_zephyr_event_dispatch,
29  NULL
30};
[09489b89]31#endif
[8262340]32
[02f55dc]33#define HM_SVC_FALLBACK         htons((unsigned short) 2104)
34
[6ea3890]35static char *owl_zephyr_dotfile(const char *name, const char *input)
36{
37  if (input != NULL)
[d4927a7]38    return g_strdup(input);
[6ea3890]39  else
[3472845]40    return g_strdup_printf("%s/%s", owl_global_get_homedir(&g), name);
[6ea3890]41}
42
[52a0f14]43#ifdef HAVE_LIBZEPHYR
[c79a047]44void owl_zephyr_initialize(void)
[52a0f14]45{
[488913a]46  Code_t ret;
[02f55dc]47  struct servent *sp;
48  struct sockaddr_in sin;
49  ZNotice_t req;
[52a0f14]50
51  /*
52   * Code modified from libzephyr's ZhmStat.c
53   *
54   * Modified to add the fd to our select loop, rather than hanging
55   * until we get an ack.
56   */
57
58  if ((ret = ZOpenPort(NULL)) != ZERR_NONE) {
59    owl_function_error("Error opening Zephyr port: %s", error_message(ret));
60    return;
61  }
[02f55dc]62
[4d86e06]63  (void) memset(&sin, 0, sizeof(struct sockaddr_in));
[02f55dc]64
65  sp = getservbyname(HM_SVCNAME, "udp");
66
67  sin.sin_port = (sp) ? sp->s_port : HM_SVC_FALLBACK;
68  sin.sin_family = AF_INET;
69
70  sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
71
[4d86e06]72  (void) memset(&req, 0, sizeof(req));
[02f55dc]73  req.z_kind = STAT;
74  req.z_port = 0;
[712caac]75  req.z_class = zstr(HM_STAT_CLASS);
76  req.z_class_inst = zstr(HM_STAT_CLIENT);
77  req.z_opcode = zstr(HM_GIMMESTATS);
78  req.z_sender = zstr("");
79  req.z_recipient = zstr("");
80  req.z_default_format = zstr("");
[02f55dc]81  req.z_message_len = 0;
[52a0f14]82
[488913a]83  if ((ret = ZSetDestAddr(&sin)) != ZERR_NONE) {
84    owl_function_error("Initializing Zephyr: %s", error_message(ret));
[52a0f14]85    return;
86  }
87
[488913a]88  if ((ret = ZSendNotice(&req, ZNOAUTH)) != ZERR_NONE) {
89    owl_function_error("Initializing Zephyr: %s", error_message(ret));
[52a0f14]90    return;
91  }
92
[18fdd5f9]93  owl_select_add_io_dispatch(ZGetFD(), OWL_IO_READ|OWL_IO_EXCEPT, &owl_zephyr_finish_initialization, NULL, NULL);
[02f55dc]94}
95
[18fdd5f9]96void owl_zephyr_finish_initialization(const owl_io_dispatch *d, void *data) {
[52a0f14]97  Code_t code;
[df569c5]98  char *perl;
[959cb85]99  GSource *event_source;
[52a0f14]100
[18fdd5f9]101  owl_select_remove_io_dispatch(d);
[52a0f14]102
103  ZClosePort();
104
105  if ((code = ZInitialize()) != ZERR_NONE) {
106    owl_function_error("Initializing Zephyr: %s", error_message(code));
107    return;
108  }
109
110  if ((code = ZOpenPort(NULL)) != ZERR_NONE) {
111    owl_function_error("Initializing Zephyr: %s", error_message(code));
112    return;
113  }
114
[959cb85]115  event_source = owl_zephyr_event_source_new(ZGetFD());
116  g_source_attach(event_source, NULL);
117  g_source_unref(event_source);
[18fdd5f9]118
[52a0f14]119  owl_global_set_havezephyr(&g);
120
121  if(g.load_initial_subs) {
122    owl_zephyr_load_initial_subs();
123  }
[a5e7ed6]124  while(deferred_subs != NULL) {
125    owl_sub_list *subs = deferred_subs->data;
126    owl_function_debugmsg("Loading %d deferred subs.", subs->nsubs);
127    owl_zephyr_loadsubs_helper(subs->subs, subs->nsubs);
128    deferred_subs = g_list_delete_link(deferred_subs, deferred_subs);
[ddbbcffa]129    g_free(subs);
[a5e7ed6]130  }
[619d864]131
132  /* zlog in if we need to */
133  if (owl_global_is_startuplogin(&g)) {
134    owl_function_debugmsg("startup: doing zlog in");
135    owl_zephyr_zlog_in();
136  }
[27964fe]137  /* check pseudo-logins if we need to */
138  if (owl_global_is_pseudologins(&g)) {
139    owl_function_debugmsg("startup: checking pseudo-logins");
140    owl_function_zephyr_buddy_check(0);
141  }
[df569c5]142
[12e291a]143  perl = owl_perlconfig_execute("BarnOwl::Zephyr::_zephyr_startup()");
[ddbbcffa]144  g_free(perl);
[52a0f14]145}
146
[c79a047]147void owl_zephyr_load_initial_subs(void) {
[7451af9]148  int ret_sd, ret_bd, ret_u;
[52a0f14]149
150  owl_function_debugmsg("startup: loading initial zephyr subs");
151
152  /* load default subscriptions */
[7451af9]153  ret_sd = owl_zephyr_loaddefaultsubs();
154
155  /* load Barnowl default subscriptions */
156  ret_bd = owl_zephyr_loadbarnowldefaultsubs();
[52a0f14]157
158  /* load subscriptions from subs file */
[7451af9]159  ret_u = owl_zephyr_loadsubs(NULL, 0);
[52a0f14]160
[7451af9]161  if (ret_sd || ret_bd || ret_u) {
[52a0f14]162    owl_function_error("Error loading zephyr subscriptions");
163  }
164
165  /* load login subscriptions */
166  if (owl_global_is_loginsubs(&g)) {
167    owl_function_debugmsg("startup: loading login subs");
168    owl_function_loadloginsubs(NULL);
169  }
170}
171#else
[c79a047]172void owl_zephyr_initialize(void)
[52a0f14]173{
174}
[02f55dc]175#endif
176
[52a0f14]177
[c79a047]178int owl_zephyr_shutdown(void)
[09489b89]179{
180#ifdef HAVE_LIBZEPHYR
[bfbf590]181  if(owl_global_is_havezephyr(&g)) {
182    unsuball();
183    ZClosePort();
184  }
[09489b89]185#endif
[32ad44d]186  return 0;
[be0a79f]187}
188
[c79a047]189int owl_zephyr_zpending(void)
[be0a79f]190{
191#ifdef HAVE_LIBZEPHYR
[8ab1f28]192  Code_t code;
193  if(owl_global_is_havezephyr(&g)) {
194    if((code = ZPending()) < 0) {
195      owl_function_debugmsg("Error (%s) in ZPending()\n",
196                            error_message(code));
197      return 0;
198    }
199    return code;
200  }
[be0a79f]201#endif
[32ad44d]202  return 0;
[be0a79f]203}
204
[959cb85]205int owl_zephyr_zqlength(void)
206{
207#ifdef HAVE_LIBZEPHYR
208  Code_t code;
209  if(owl_global_is_havezephyr(&g)) {
210    if((code = ZQLength()) < 0) {
211      owl_function_debugmsg("Error (%s) in ZQLength()\n",
212                            error_message(code));
213      return 0;
214    }
215    return code;
216  }
217#endif
218  return 0;
219}
220
[c79a047]221const char *owl_zephyr_get_realm(void)
[09489b89]222{
223#ifdef HAVE_LIBZEPHYR
[32ad44d]224  if (owl_global_is_havezephyr(&g))
225    return(ZGetRealm());
[09489b89]226#endif
[32ad44d]227  return "";
[09489b89]228}
229
[c79a047]230const char *owl_zephyr_get_sender(void)
[09489b89]231{
232#ifdef HAVE_LIBZEPHYR
[32ad44d]233  if (owl_global_is_havezephyr(&g))
234    return(ZGetSender());
[09489b89]235#endif
[32ad44d]236  return "";
[09489b89]237}
238
[f6050ee]239#ifdef HAVE_LIBZEPHYR
[93e883d]240int owl_zephyr_loadsubs_helper(ZSubscription_t subs[], int count)
241{
[18105584]242  int ret = 0;
[c73a22d]243  Code_t code;
244
[a5e7ed6]245  if (owl_global_is_havezephyr(&g)) {
246    int i;
247    /* sub without defaults */
[c73a22d]248    code = ZSubscribeToSansDefaults(subs, count, 0);
249    if (code != ZERR_NONE) {
250      owl_function_error("Error subscribing to zephyr notifications: %s",
251                         error_message(code));
[a5e7ed6]252      ret=-2;
253    }
[93e883d]254
[a5e7ed6]255    /* free stuff */
256    for (i=0; i<count; i++) {
[ddbbcffa]257      g_free(subs[i].zsub_class);
258      g_free(subs[i].zsub_classinst);
259      g_free(subs[i].zsub_recipient);
[a5e7ed6]260    }
[bb2c60d]261
[ddbbcffa]262    g_free(subs);
[a5e7ed6]263  } else {
[96828e4]264    owl_sub_list *s = g_new(owl_sub_list, 1);
[a5e7ed6]265    s->subs = subs;
266    s->nsubs = count;
267    deferred_subs = g_list_append(deferred_subs, s);
268  }
[d21efbc]269
[93e883d]270  return ret;
271}
[f6050ee]272#endif
[93e883d]273
[7451af9]274/* Load zephyr subscriptions from 'filename'.  If 'filename' is NULL,
[95474d7]275 * the default file $HOME/.zephyr.subs will be used.
276 *
277 * Returns 0 on success.  If the file does not exist, return -1 if
278 * 'error_on_nofile' is 1, otherwise return 0.  Return -1 if the file
279 * exists but can not be read.  Return -2 if there is a failure from
280 * zephyr to load the subscriptions.
[2de4f20]281 */
[e19eb97]282int owl_zephyr_loadsubs(const char *filename, int error_on_nofile)
[31e48a3]283{
[be0a79f]284#ifdef HAVE_LIBZEPHYR
[7d4fbcd]285  FILE *file;
286  char *tmp, *start;
[b7ee89b]287  char *buffer = NULL;
288  char *subsfile;
[bb2c60d]289  ZSubscription_t *subs;
290  int subSize = 1024;
[b7ee89b]291  int count;
[4357be8]292  struct stat statbuff;
[7d4fbcd]293
[96828e4]294  subs = g_new(ZSubscription_t, subSize);
[6ea3890]295  subsfile = owl_zephyr_dotfile(".zephyr.subs", filename);
[b7ee89b]296
297  if (stat(subsfile, &statbuff) != 0) {
[ddbbcffa]298    g_free(subsfile);
[b7ee89b]299    if (error_on_nofile == 1)
300      return -1;
301    return 0;
[95474d7]302  }
[4357be8]303
[8262340]304  ZResetAuthentication();
[b7ee89b]305  count = 0;
306  file = fopen(subsfile, "r");
[ddbbcffa]307  g_free(subsfile);
[b7ee89b]308  if (!file)
309    return -1;
310  while (owl_getline(&buffer, file)) {
311    if (buffer[0] == '#' || buffer[0] == '\n')
312        continue;
313
314    if (buffer[0] == '-')
315      start = buffer + 1;
316    else
317      start = buffer;
318
[bb2c60d]319    if (count >= subSize) {
[d21efbc]320      subSize *= 2;
[35b6eb9]321      subs = g_renew(ZSubscription_t, subs, subSize);
[93e883d]322    }
[95474d7]323   
324    /* add it to the list of subs */
[b7ee89b]325    if ((tmp = strtok(start, ",\n\r")) == NULL)
326      continue;
[d4927a7]327    subs[count].zsub_class = g_strdup(tmp);
[b7ee89b]328    if ((tmp=strtok(NULL, ",\n\r")) == NULL)
329      continue;
[d4927a7]330    subs[count].zsub_classinst = g_strdup(tmp);
[b7ee89b]331    if ((tmp = strtok(NULL, " \t\n\r")) == NULL)
332      continue;
[d4927a7]333    subs[count].zsub_recipient = g_strdup(tmp);
[b7ee89b]334
[bb2c60d]335    /* if it started with '-' then add it to the global punt list, and
336     * remove it from the list of subs. */
[b7ee89b]337    if (buffer[0] == '-') {
[95474d7]338      owl_function_zpunt(subs[count].zsub_class, subs[count].zsub_classinst, subs[count].zsub_recipient, 0);
[ddbbcffa]339      g_free(subs[count].zsub_class);
340      g_free(subs[count].zsub_classinst);
341      g_free(subs[count].zsub_recipient);
[b7ee89b]342    } else {
[bb2c60d]343      count++;
[95474d7]344    }
[7d4fbcd]345  }
[95474d7]346  fclose(file);
[b7ee89b]347  if (buffer)
[ddbbcffa]348    g_free(buffer);
[7d4fbcd]349
[b7ee89b]350  return owl_zephyr_loadsubs_helper(subs, count);
[7451af9]351#else
[b7ee89b]352  return 0;
[7451af9]353#endif
354}
355
356/* Load default Barnowl subscriptions
357 *
358 * Returns 0 on success.
359 * Return -2 if there is a failure from zephyr to load the subscriptions.
360 */
[c79a047]361int owl_zephyr_loadbarnowldefaultsubs(void)
[7451af9]362{
363#ifdef HAVE_LIBZEPHYR
364  ZSubscription_t *subs;
365  int subSize = 10; /* Max Barnowl default subs we allow */
366  int count, ret;
367
[96828e4]368  subs = g_new(ZSubscription_t, subSize);
[7451af9]369  ZResetAuthentication();
370  count=0;
371
[d4927a7]372  subs[count].zsub_class=g_strdup("message");
373  subs[count].zsub_classinst=g_strdup("*");
374  subs[count].zsub_recipient=g_strdup("%me%");
[7451af9]375  count++;
376
377  ret = owl_zephyr_loadsubs_helper(subs, count);
[7d4fbcd]378  return(ret);
[be0a79f]379#else
380  return(0);
381#endif
[7d4fbcd]382}
383
[c79a047]384int owl_zephyr_loaddefaultsubs(void)
[4357be8]385{
[40d834a]386#ifdef HAVE_LIBZEPHYR
[c73a22d]387  Code_t ret;
388
[2c5ee3e]389  if (owl_global_is_havezephyr(&g)) {
390    ZSubscription_t subs[10];
[c73a22d]391
392    ret = ZSubscribeTo(subs, 0, 0);
393    if (ret != ZERR_NONE) {
394      owl_function_error("Error subscribing to default zephyr notifications: %s.",
395                           error_message(ret));
[2c5ee3e]396      return(-1);
397    }
[4357be8]398  }
399  return(0);
[40d834a]400#else
401  return(0);
402#endif
[4357be8]403}
404
[e19eb97]405int owl_zephyr_loadloginsubs(const char *filename)
[31e48a3]406{
[be0a79f]407#ifdef HAVE_LIBZEPHYR
[7d4fbcd]408  FILE *file;
[d21efbc]409  ZSubscription_t *subs;
410  int numSubs = 100;
[b7ee89b]411  char *subsfile;
412  char *buffer = NULL;
413  int count;
[4357be8]414  struct stat statbuff;
[7d4fbcd]415
[96828e4]416  subs = g_new(ZSubscription_t, numSubs);
[6ea3890]417  subsfile = owl_zephyr_dotfile(".anyone", filename);
[4357be8]418
[922f589]419  if (stat(subsfile, &statbuff) == -1) {
[ddbbcffa]420    g_free(subs);
421    g_free(subsfile);
[b7ee89b]422    return 0;
[922f589]423  }
[7d4fbcd]424
[8262340]425  ZResetAuthentication();
[b7ee89b]426  count = 0;
427  file = fopen(subsfile, "r");
[ddbbcffa]428  g_free(subsfile);
[7d4fbcd]429  if (file) {
[b7ee89b]430    while (owl_getline_chomp(&buffer, file)) {
431      if (buffer[0] == '\0' || buffer[0] == '#')
432        continue;
433
[d21efbc]434      if (count == numSubs) {
435        numSubs *= 2;
[35b6eb9]436        subs = g_renew(ZSubscription_t, subs, numSubs);
[d21efbc]437      }
[7d4fbcd]438
[d4927a7]439      subs[count].zsub_class = g_strdup("login");
440      subs[count].zsub_recipient = g_strdup("*");
[b7ee89b]441      subs[count].zsub_classinst = long_zuser(buffer);
[7d4fbcd]442
443      count++;
444    }
445    fclose(file);
446  } else {
[b7ee89b]447    return 0;
[7d4fbcd]448  }
[3b8a563]449  g_free(buffer);
[7d4fbcd]450
[b7ee89b]451  return owl_zephyr_loadsubs_helper(subs, count);
[be0a79f]452#else
[b7ee89b]453  return 0;
[be0a79f]454#endif
[7d4fbcd]455}
456
[c79a047]457void unsuball(void)
[31e48a3]458{
[be0a79f]459#if HAVE_LIBZEPHYR
[00842c3]460  Code_t ret;
[8262340]461
462  ZResetAuthentication();
[00842c3]463  ret = ZCancelSubscriptions(0);
464  if (ret != ZERR_NONE)
465    owl_function_error("Zephyr: Cancelling subscriptions: %s",
466                       error_message(ret));
[be0a79f]467#endif
[7d4fbcd]468}
469
[e19eb97]470int owl_zephyr_sub(const char *class, const char *inst, const char *recip)
[31e48a3]471{
[be0a79f]472#ifdef HAVE_LIBZEPHYR
[7d4fbcd]473  ZSubscription_t subs[5];
[c73a22d]474  Code_t ret;
[7d4fbcd]475
[712caac]476  subs[0].zsub_class=zstr(class);
477  subs[0].zsub_classinst=zstr(inst);
478  subs[0].zsub_recipient=zstr(recip);
[7d4fbcd]479
[8262340]480  ZResetAuthentication();
[c73a22d]481  ret = ZSubscribeTo(subs, 1, 0);
482  if (ret != ZERR_NONE) {
483    owl_function_error("Error subbing to <%s,%s,%s>: %s",
484                       class, inst, recip,
485                       error_message(ret));
[97cd00be]486    return(-2);
[7d4fbcd]487  }
488  return(0);
[be0a79f]489#else
490  return(0);
491#endif
[7d4fbcd]492}
493
494
[e19eb97]495int owl_zephyr_unsub(const char *class, const char *inst, const char *recip)
[31e48a3]496{
[be0a79f]497#ifdef HAVE_LIBZEPHYR
[7d4fbcd]498  ZSubscription_t subs[5];
[c73a22d]499  Code_t ret;
[7d4fbcd]500
[712caac]501  subs[0].zsub_class=zstr(class);
502  subs[0].zsub_classinst=zstr(inst);
503  subs[0].zsub_recipient=zstr(recip);
[7d4fbcd]504
[8262340]505  ZResetAuthentication();
[c73a22d]506  ret = ZUnsubscribeTo(subs, 1, 0);
507  if (ret != ZERR_NONE) {
508    owl_function_error("Error unsubbing from <%s,%s,%s>: %s",
509                       class, inst, recip,
510                       error_message(ret));
[97cd00be]511    return(-2);
[7d4fbcd]512  }
513  return(0);
[be0a79f]514#else
515  return(0);
516#endif
[7d4fbcd]517}
518
[b0430a6]519/* return a pointer to the data in the Jth field, (NULL terminated by
520 * definition).  Caller must free the return.
521 */
[be0a79f]522#ifdef HAVE_LIBZEPHYR
[1077891a]523char *owl_zephyr_get_field(const ZNotice_t *n, int j)
[31e48a3]524{
[7d4fbcd]525  int i, count, save;
526
[128171a]527  /* If there's no message here, just run along now */
528  if (n->z_message_len == 0)
[d4927a7]529    return(g_strdup(""));
[128171a]530
[7d4fbcd]531  count=save=0;
532  for (i=0; i<n->z_message_len; i++) {
533    if (n->z_message[i]=='\0') {
534      count++;
535      if (count==j) {
536        /* just found the end of the field we're looking for */
[d4927a7]537        return(g_strdup(n->z_message+save));
[7d4fbcd]538      } else {
539        save=i+1;
540      }
541    }
542  }
[b0430a6]543  /* catch the last field, which might not be null terminated */
[7d4fbcd]544  if (count==j-1) {
[fc7481a]545    return g_strndup(n->z_message + save, n->z_message_len - save);
[7d4fbcd]546  }
[b0430a6]547
[d4927a7]548  return(g_strdup(""));
[7d4fbcd]549}
[5376a95]550
[1077891a]551char *owl_zephyr_get_field_as_utf8(const ZNotice_t *n, int j)
[5376a95]552{
553  int i, count, save;
554
555  /* If there's no message here, just run along now */
556  if (n->z_message_len == 0)
[d4927a7]557    return(g_strdup(""));
[5376a95]558
559  count=save=0;
560  for (i = 0; i < n->z_message_len; i++) {
561    if (n->z_message[i]=='\0') {
562      count++;
563      if (count == j) {
564        /* just found the end of the field we're looking for */
[6201646]565        return(owl_validate_or_convert(n->z_message + save));
[5376a95]566      } else {
567        save = i + 1;
568      }
569    }
570  }
571  /* catch the last field, which might not be null terminated */
572  if (count == j - 1) {
[6201646]573    char *tmp, *out;
[fc7481a]574    tmp = g_strndup(n->z_message + save, n->z_message_len - save);
[6201646]575    out = owl_validate_or_convert(tmp);
[ddbbcffa]576    g_free(tmp);
[6201646]577    return out;
[5376a95]578  }
579
[d4927a7]580  return(g_strdup(""));
[5376a95]581}
[09489b89]582#else
[701a184]583char *owl_zephyr_get_field(void *n, int j)
[09489b89]584{
[d4927a7]585  return(g_strdup(""));
[09489b89]586}
[5577606]587char *owl_zephyr_get_field_as_utf8(void *n, int j)
[5376a95]588{
589  return owl_zephyr_get_field(n, j);
590}
[be0a79f]591#endif
[7d4fbcd]592
[b0430a6]593
[be0a79f]594#ifdef HAVE_LIBZEPHYR
[1077891a]595int owl_zephyr_get_num_fields(const ZNotice_t *n)
[31e48a3]596{
[7d4fbcd]597  int i, fields;
598
[50e29e3]599  if(n->z_message_len == 0)
600    return 0;
601
[7d4fbcd]602  fields=1;
603  for (i=0; i<n->z_message_len; i++) {
604    if (n->z_message[i]=='\0') fields++;
605  }
606 
607  return(fields);
608}
[09489b89]609#else
[1077891a]610int owl_zephyr_get_num_fields(const void *n)
[09489b89]611{
612  return(0);
613}
[be0a79f]614#endif
[7d4fbcd]615
[be0a79f]616#ifdef HAVE_LIBZEPHYR
[bf73bdd]617/* return a pointer to the message, place the message length in k
618 * caller must free the return
619 */
[c08c70a]620char *owl_zephyr_get_message(const ZNotice_t *n, const owl_message *m)
[31e48a3]621{
[c518676]622#define OWL_NFIELDS     5
623  int i;
624  char *fields[OWL_NFIELDS + 1];
625  char *msg = NULL;
626
[405d5e6]627  /* don't let ping messages have a body */
[7d4fbcd]628  if (!strcasecmp(n->z_opcode, "ping")) {
[d4927a7]629    return(g_strdup(""));
[7d4fbcd]630  }
631
[c518676]632  for(i = 0; i < OWL_NFIELDS; i++)
633    fields[i + 1] = owl_zephyr_get_field(n, i + 1);
634
[a1bb198]635  /* deal with MIT NOC messages */
[85d1795]636  if (!strcasecmp(n->z_default_format, "@center(@bold(NOC Message))\n\n@bold(Sender:) $1 <$sender>\n@bold(Time:  ) $time\n\n@italic($opcode service on $instance $3.) $4\n")) {
[a1bb198]637
[c518676]638    msg = g_strdup_printf("%s service on %s %s\n%s", n->z_opcode, n->z_class_inst, fields[3], fields[4]);
[a1bb198]639  }
[fba0f96]640  /* deal with MIT Discuss messages */
[e2a620b]641  else if (!strcasecmp(n->z_default_format, "New transaction [$1] entered in $2\nFrom: $3 ($5)\nSubject: $4") ||
642           !strcasecmp(n->z_default_format, "New transaction [$1] entered in $2\nFrom: $3\nSubject: $4")) {
[fba0f96]643   
[c518676]644    msg = g_strdup_printf("New transaction [%s] entered in %s\nFrom: %s (%s)\nSubject: %s",
645                          fields[1], fields[2], fields[3], fields[5], fields[4]);
[fba0f96]646  }
[85d1795]647  /* deal with MIT Moira messages */
648  else if (!strcasecmp(n->z_default_format, "MOIRA $instance on $fromhost:\n $message\n")) {
[c518676]649    msg = g_strdup_printf("MOIRA %s on %s: %s",
650                          n->z_class_inst,
651                          owl_message_get_hostname(m),
652                          fields[1]);
653  } else {
654    if (owl_zephyr_get_num_fields(n) == 1)
655      msg = g_strdup(fields[1]);
656    else
657      msg = g_strdup(fields[2]);
[85d1795]658  }
[405d5e6]659
[c518676]660  for (i = 0; i < OWL_NFIELDS; i++)
661    g_free(fields[i + 1]);
662
663  return msg;
[7d4fbcd]664}
[be0a79f]665#endif
[7d4fbcd]666
[be0a79f]667#ifdef HAVE_LIBZEPHYR
[1077891a]668const char *owl_zephyr_get_zsig(const ZNotice_t *n, int *k)
[31e48a3]669{
[7d4fbcd]670  /* return a pointer to the zsig if there is one */
671
[405d5e6]672  /* message length 0? No zsig */
[7d4fbcd]673  if (n->z_message_len==0) {
674    *k=0;
675    return("");
676  }
[405d5e6]677
[85d1795]678  /* If there's only one field, no zsig */
679  if (owl_zephyr_get_num_fields(n) == 1) {
680    *k=0;
[405d5e6]681    return("");
682  }
683
684  /* Everything else is field 1 */
[7d4fbcd]685  *k=strlen(n->z_message);
686  return(n->z_message);
687}
[09489b89]688#else
[1077891a]689const char *owl_zephyr_get_zsig(const void *n, int *k)
[09489b89]690{
691  return("");
692}
[be0a79f]693#endif
[7d4fbcd]694
[e19eb97]695int send_zephyr(const char *opcode, const char *zsig, const char *class, const char *instance, const char *recipient, const char *message)
[31e48a3]696{
[be0a79f]697#ifdef HAVE_LIBZEPHYR
[c73a22d]698  Code_t ret;
[7d4fbcd]699  ZNotice_t notice;
700   
701  memset(&notice, 0, sizeof(notice));
702
[8262340]703  ZResetAuthentication();
[8ba37ec]704
705  if (!zsig) zsig="";
[8262340]706 
[7d4fbcd]707  notice.z_kind=ACKED;
708  notice.z_port=0;
[712caac]709  notice.z_class=zstr(class);
710  notice.z_class_inst=zstr(instance);
[21882032]711  notice.z_sender=NULL;
[7d4fbcd]712  if (!strcmp(recipient, "*") || !strcmp(recipient, "@")) {
[712caac]713    notice.z_recipient=zstr("");
[21882032]714    if (*owl_global_get_zsender(&g))
[712caac]715        notice.z_sender=zstr(owl_global_get_zsender(&g));
[7d4fbcd]716  } else {
[712caac]717    notice.z_recipient=zstr(recipient);
[7d4fbcd]718  }
[712caac]719  notice.z_default_format=zstr("Class $class, Instance $instance:\nTo: @bold($recipient) at $time $date\nFrom: @bold{$1 <$sender>}\n\n$2");
720  if (opcode) notice.z_opcode=zstr(opcode);
[7d4fbcd]721
[56330ff]722  notice.z_message_len=strlen(zsig)+1+strlen(message);
[96828e4]723  notice.z_message=g_new(char, notice.z_message_len+10);
[56330ff]724  strcpy(notice.z_message, zsig);
725  memcpy(notice.z_message+strlen(zsig)+1, message, strlen(message));
[7d4fbcd]726
727  /* ret=ZSendNotice(&notice, ZAUTH); */
728  ret=ZSrvSendNotice(&notice, ZAUTH, send_zephyr_helper);
729 
730  /* free then check the return */
[ddbbcffa]731  g_free(notice.z_message);
[7d4fbcd]732  ZFreeNotice(&notice);
[c73a22d]733  if (ret != ZERR_NONE) {
734    owl_function_error("Error sending zephyr: %s", error_message(ret));
[7d4fbcd]735    return(ret);
736  }
737  return(0);
[be0a79f]738#else
739  return(0);
740#endif
[7d4fbcd]741}
742
[be0a79f]743#ifdef HAVE_LIBZEPHYR
[31e48a3]744Code_t send_zephyr_helper(ZNotice_t *notice, char *buf, int len, int wait)
745{
[7d4fbcd]746  return(ZSendPacket(buf, len, 0));
747}
[be0a79f]748#endif
[7d4fbcd]749
[e19eb97]750void send_ping(const char *to, const char *zclass, const char *zinstance)
[31e48a3]751{
[be0a79f]752#ifdef HAVE_LIBZEPHYR
[3ef779b]753  send_zephyr("PING", "", zclass, zinstance, to, "");
[be0a79f]754#endif
[7d4fbcd]755}
756
[be0a79f]757#ifdef HAVE_LIBZEPHYR
[1077891a]758void owl_zephyr_handle_ack(const ZNotice_t *retnotice)
[31e48a3]759{
[7d4fbcd]760  char *tmp;
761 
762  /* if it's an HMACK ignore it */
763  if (retnotice->z_kind == HMACK) return;
[aecf3e6]764
[7d4fbcd]765  if (retnotice->z_kind == SERVNAK) {
[ec6ff52]766    owl_function_error("Authorization failure sending zephyr");
[7d4fbcd]767  } else if ((retnotice->z_kind != SERVACK) || !retnotice->z_message_len) {
[ec6ff52]768    owl_function_error("Detected server failure while receiving acknowledgement");
[7d4fbcd]769  } else if (!strcmp(retnotice->z_message, ZSRVACK_SENT)) {
770    if (!strcasecmp(retnotice->z_opcode, "ping")) {
771      return;
772    } else {
[d73e3af]773      if (strcasecmp(retnotice->z_recipient, ""))
[1e550b2]774      { /* personal */
[d73e3af]775        tmp=short_zuser(retnotice->z_recipient);
776        if(!strcasecmp(retnotice->z_class, "message") &&
777           !strcasecmp(retnotice->z_class_inst, "personal")) {
778          owl_function_makemsg("Message sent to %s.", tmp);
[1e550b2]779        } else if(!strcasecmp(retnotice->z_class, "message")) { /* instanced, but not classed, personal */
[d73e3af]780          owl_function_makemsg("Message sent to %s on -i %s\n", tmp, retnotice->z_class_inst);
[1e550b2]781        } else { /* classed personal */
[d73e3af]782          owl_function_makemsg("Message sent to %s on -c %s -i %s\n", tmp, retnotice->z_class, retnotice->z_class_inst);
783        }
[ddbbcffa]784        g_free(tmp);
[d73e3af]785      } else {
[1e550b2]786        /* class / instance message */
[d73e3af]787          owl_function_makemsg("Message sent to -c %s -i %s\n", retnotice->z_class, retnotice->z_class_inst);
788      }
[7d4fbcd]789    }
790  } else if (!strcmp(retnotice->z_message, ZSRVACK_NOTSENT)) {
[44f32fb]791    if (retnotice->z_recipient == NULL
[60c2e1e]792        || *retnotice->z_recipient == 0
[44f32fb]793        || *retnotice->z_recipient == '@') {
[e3a75ed]794      char *buff;
[44f32fb]795      owl_function_error("No one subscribed to class %s", retnotice->z_class);
[e3a75ed]796      buff = g_strdup_printf("Could not send message to class %s: no one subscribed.\n", retnotice->z_class);
[9119a47]797      owl_function_adminmsg("", buff);
[e3a75ed]798      g_free(buff);
[7d4fbcd]799    } else {
[e3a75ed]800      char *buff;
[24ccc01]801      owl_zwrite zw;
802
[4b464a4]803      tmp = short_zuser(retnotice->z_recipient);
[44f32fb]804      owl_function_error("%s: Not logged in or subscribing.", tmp);
[3ef779b]805      /*
806       * These error messages are often over 80 chars, but users who want to
807       * see the whole thing can scroll to the side, and for those with wide
808       * terminals or who don't care, not splitting saves a line in the UI
809       */
810      if(strcasecmp(retnotice->z_class, "message")) {
[e3a75ed]811        buff = g_strdup_printf(
[10e3963]812                 "Could not send message to %s: "
[3ef779b]813                 "not logged in or subscribing to class %s, instance %s.\n",
[10e3963]814                 tmp,
[1151f0b]815                 retnotice->z_class,
816                 retnotice->z_class_inst);
[3ef779b]817      } else if(strcasecmp(retnotice->z_class_inst, "personal")) {
[e3a75ed]818        buff = g_strdup_printf(
[3ef779b]819                 "Could not send message to %s: "
820                 "not logged in or subscribing to instance %s.\n",
821                 tmp,
822                 retnotice->z_class_inst);
[44f32fb]823      } else {
[e3a75ed]824        buff = g_strdup_printf(
[10e3963]825                 "Could not send message to %s: "
826                 "not logged in or subscribing to messages.\n",
827                 tmp);
[44f32fb]828      }
[9119a47]829      owl_function_adminmsg("", buff);
[24ccc01]830
831      memset(&zw, 0, sizeof(zw));
[d4927a7]832      zw.class = g_strdup(retnotice->z_class);
833      zw.inst  = g_strdup(retnotice->z_class_inst);
[fe3b017]834      zw.realm = g_strdup("");
[d4927a7]835      zw.opcode = g_strdup(retnotice->z_opcode);
836      zw.zsig   = g_strdup("");
[24ccc01]837      owl_list_create(&(zw.recips));
[fe3b017]838      owl_list_append_element(&(zw.recips), g_strdup(retnotice->z_recipient));
[24ccc01]839
840      owl_log_outgoing_zephyr_error(&zw, buff);
841
[c230bc1]842      owl_zwrite_cleanup(&zw);
[e3a75ed]843      g_free(buff);
[ddbbcffa]844      g_free(tmp);
[7d4fbcd]845    }
846  } else {
[ec6ff52]847    owl_function_error("Internal error on ack (%s)", retnotice->z_message);
[7d4fbcd]848  }
849}
[09489b89]850#else
[1077891a]851void owl_zephyr_handle_ack(const void *retnotice)
[09489b89]852{
853}
[be0a79f]854#endif
[7d4fbcd]855
[be0a79f]856#ifdef HAVE_LIBZEPHYR
[1077891a]857int owl_zephyr_notice_is_ack(const ZNotice_t *n)
[31e48a3]858{
[7d4fbcd]859  if (n->z_kind == SERVNAK || n->z_kind == SERVACK || n->z_kind == HMACK) {
860    if (!strcasecmp(n->z_class, LOGIN_CLASS)) return(0);
861    return(1);
862  }
863  return(0);
864}
[09489b89]865#else
[1077891a]866int owl_zephyr_notice_is_ack(const void *n)
[09489b89]867{
868  return(0);
869}
[be0a79f]870#endif
[7d4fbcd]871 
[c08c70a]872void owl_zephyr_zaway(const owl_message *m)
[31e48a3]873{
[be0a79f]874#ifdef HAVE_LIBZEPHYR
[7c8060d0]875  char *tmpbuff, *myuser, *to;
[987cf3f]876  owl_zwrite *z;
[7d4fbcd]877 
[aa2f6364]878  /* bail if it doesn't look like a message we should reply to.  Some
[2de4f20]879   * of this defined by the way zaway(1) works
880   */
[7d4fbcd]881  if (strcasecmp(owl_message_get_class(m), "message")) return;
882  if (strcasecmp(owl_message_get_recipient(m), ZGetSender())) return;
883  if (!strcasecmp(owl_message_get_sender(m), "")) return;
884  if (!strcasecmp(owl_message_get_opcode(m), "ping")) return;
885  if (!strcasecmp(owl_message_get_opcode(m), "auto")) return;
[d023c25]886  if (!strcasecmp(owl_message_get_zsig(m), "Automated reply:")) return;
[7d4fbcd]887  if (!strcasecmp(owl_message_get_sender(m), ZGetSender())) return;
[9854278]888  if (owl_message_get_attribute_value(m, "isauto")) return;
[7d4fbcd]889
[7c8060d0]890  if (owl_global_is_smartstrip(&g)) {
[e3d9c77]891    to=owl_zephyr_smartstripped_user(owl_message_get_sender(m));
[7c8060d0]892  } else {
[d4927a7]893    to=g_strdup(owl_message_get_sender(m));
[7c8060d0]894  }
895
[7d4fbcd]896  send_zephyr("",
897              "Automated reply:",
898              owl_message_get_class(m),
899              owl_message_get_instance(m),
[7c8060d0]900              to,
[7d4fbcd]901              owl_global_get_zaway_msg(&g));
902
[7c8060d0]903  myuser=short_zuser(to);
[aa2f6364]904  if (!strcasecmp(owl_message_get_instance(m), "personal")) {
[eb8d9c1]905    tmpbuff = owl_string_build_quoted("zwrite %q", myuser);
[aa2f6364]906  } else {
[eb8d9c1]907    tmpbuff = owl_string_build_quoted("zwrite -i %q %q", owl_message_get_instance(m), myuser);
[aa2f6364]908  }
[ddbbcffa]909  g_free(myuser);
910  g_free(to);
[aa2f6364]911
[987cf3f]912  z = owl_zwrite_new(tmpbuff);
[bb85767]913  g_free(tmpbuff);
914  if (z == NULL) {
915    owl_function_error("Error creating outgoing zephyr.");
916    return;
917  }
[987cf3f]918  owl_zwrite_set_message(z, owl_global_get_zaway_msg(&g));
919  owl_zwrite_set_zsig(z, "Automated reply:");
920
[7d4fbcd]921  /* display the message as an admin message in the receive window */
[e5da3fe]922  owl_function_add_outgoing_zephyrs(z);
[987cf3f]923  owl_zwrite_delete(z);
[be0a79f]924#endif
[7d4fbcd]925}
926
[be0a79f]927#ifdef HAVE_LIBZEPHYR
[31e48a3]928void owl_zephyr_hackaway_cr(ZNotice_t *n)
929{
[7d4fbcd]930  /* replace \r's with ' '.  Gross-ish */
931  int i;
932
933  for (i=0; i<n->z_message_len; i++) {
934    if (n->z_message[i]=='\r') {
935      n->z_message[i]=' ';
936    }
937  }
938}
[be0a79f]939#endif
[7d4fbcd]940
[dca3b27]941char *owl_zephyr_zlocate(const char *user, int auth)
[31e48a3]942{
[be0a79f]943#ifdef HAVE_LIBZEPHYR
[7d4fbcd]944  int ret, numlocs;
945  int one = 1;
946  ZLocations_t locations;
947  char *myuser;
[dca3b27]948  char *p, *result;
949
[8262340]950  ZResetAuthentication();
[dca3b27]951  ret = ZLocateUser(zstr(user), &numlocs, auth ? ZAUTH : ZNOAUTH);
952  if (ret != ZERR_NONE)
[3472845]953    return g_strdup_printf("Error locating user %s: %s\n",
954                           user, error_message(ret));
[dca3b27]955
956  myuser = short_zuser(user);
957  if (numlocs == 0) {
[3472845]958    result = g_strdup_printf("%s: Hidden or not logged in\n", myuser);
[dca3b27]959  } else {
[d4927a7]960    result = g_strdup("");
[dca3b27]961    for (; numlocs; numlocs--) {
962      ZGetLocations(&locations, &one);
[3472845]963      p = g_strdup_printf("%s%s: %s\t%s\t%s\n",
[dca3b27]964                          result, myuser,
965                          locations.host ? locations.host : "?",
966                          locations.tty ? locations.tty : "?",
967                          locations.time ? locations.time : "?");
[ddbbcffa]968      g_free(result);
[dca3b27]969      result = p;
970    }
[7d4fbcd]971  }
[ddbbcffa]972  g_free(myuser);
[7d4fbcd]973
[dca3b27]974  return result;
975#else
[d4927a7]976  return g_strdup("");
[be0a79f]977#endif
[7d4fbcd]978}
[bde7714]979
[e19eb97]980void owl_zephyr_addsub(const char *filename, const char *class, const char *inst, const char *recip)
[31e48a3]981{
[be0a79f]982#ifdef HAVE_LIBZEPHYR
[b7ee89b]983  char *line, *subsfile, *s = NULL;
[bde7714]984  FILE *file;
[b7ee89b]985  int duplicate = 0;
[bde7714]986
[b7ee89b]987  line = owl_zephyr_makesubline(class, inst, recip);
[6ea3890]988  subsfile = owl_zephyr_dotfile(".zephyr.subs", filename);
[bde7714]989
[74037d9]990  /* if the file already exists, check to see if the sub is already there */
[b7ee89b]991  file = fopen(subsfile, "r");
[74037d9]992  if (file) {
[b7ee89b]993    while (owl_getline(&s, file)) {
994      if (strcasecmp(s, line) == 0) {
[74037d9]995        owl_function_error("Subscription already present in %s", subsfile);
[b7ee89b]996        duplicate++;
[74037d9]997      }
[bde7714]998    }
[99dabee]999    fclose(file);
[ddbbcffa]1000    g_free(s);
[bde7714]1001  }
1002
[b7ee89b]1003  if (!duplicate) {
1004    file = fopen(subsfile, "a");
1005    if (file) {
1006      fputs(line, file);
1007      fclose(file);
1008      owl_function_makemsg("Subscription added");
1009    } else {
1010      owl_function_error("Error opening file %s for writing", subsfile);
1011    }
[bde7714]1012  }
[b7ee89b]1013
[ddbbcffa]1014  g_free(line);
[be0a79f]1015#endif
[bde7714]1016}
1017
[e19eb97]1018void owl_zephyr_delsub(const char *filename, const char *class, const char *inst, const char *recip)
[31e48a3]1019{
[be0a79f]1020#ifdef HAVE_LIBZEPHYR
[b2a91b6]1021  char *line, *subsfile;
[da60ba9]1022  int linesdeleted;
[bde7714]1023 
1024  line=owl_zephyr_makesubline(class, inst, recip);
[b2a91b6]1025  line[strlen(line)-1]='\0';
[bde7714]1026
[6ea3890]1027  subsfile = owl_zephyr_dotfile(".zephyr.subs", filename);
[b2a91b6]1028 
[da60ba9]1029  linesdeleted = owl_util_file_deleteline(subsfile, line, 1);
1030  if (linesdeleted > 0) {
1031    owl_function_makemsg("Subscription removed");
[5fca55f]1032  } else if (linesdeleted == 0) {
[da60ba9]1033    owl_function_error("No subscription present in %s", subsfile);
1034  }
[ddbbcffa]1035  g_free(subsfile);
1036  g_free(line);
[be0a79f]1037#endif
[bde7714]1038}
1039
[b2a91b6]1040/* caller must free the return */
[e19eb97]1041char *owl_zephyr_makesubline(const char *class, const char *inst, const char *recip)
[31e48a3]1042{
[3472845]1043  return g_strdup_printf("%s,%s,%s\n", class, inst, !strcmp(recip, "") ? "*" : recip);
[bde7714]1044}
[31e48a3]1045
1046
1047void owl_zephyr_zlog_in(void)
1048{
[be0a79f]1049#ifdef HAVE_LIBZEPHYR
[31e48a3]1050  ZResetAuthentication();
[7d969f3]1051
[f203cad]1052  /* ZSetLocation, and store the default value as the current value */
1053  owl_global_set_exposure(&g, owl_global_get_default_exposure(&g));
[be0a79f]1054#endif
[31e48a3]1055}
1056
1057void owl_zephyr_zlog_out(void)
1058{
[be0a79f]1059#ifdef HAVE_LIBZEPHYR
[7d969f3]1060  Code_t ret;
[31e48a3]1061
1062  ZResetAuthentication();
[7d969f3]1063  ret = ZUnsetLocation();
1064  if (ret != ZERR_NONE)
1065    owl_function_error("Error unsetting location: %s", error_message(ret));
[be0a79f]1066#endif
[31e48a3]1067}
1068
[e19eb97]1069void owl_zephyr_addbuddy(const char *name)
[65ad073]1070{
1071  char *filename;
1072  FILE *file;
1073 
[6ea3890]1074  filename = owl_zephyr_dotfile(".anyone", NULL);
1075  file = fopen(filename, "a");
[ddbbcffa]1076  g_free(filename);
[65ad073]1077  if (!file) {
[ec6ff52]1078    owl_function_error("Error opening zephyr buddy file for append");
[65ad073]1079    return;
1080  }
1081  fprintf(file, "%s\n", name);
1082  fclose(file);
1083}
1084
[e19eb97]1085void owl_zephyr_delbuddy(const char *name)
[65ad073]1086{
1087  char *filename;
1088
[6ea3890]1089  filename = owl_zephyr_dotfile(".anyone", NULL);
[65ad073]1090  owl_util_file_deleteline(filename, name, 0);
[ddbbcffa]1091  g_free(filename);
[65ad073]1092}
[9381782]1093
1094/* return auth string */
[09489b89]1095#ifdef HAVE_LIBZEPHYR
[1077891a]1096const char *owl_zephyr_get_authstr(const ZNotice_t *n)
[9381782]1097{
1098
[f12d199]1099  if (!n) return("UNKNOWN");
1100
1101  if (n->z_auth == ZAUTH_FAILED) {
[9381782]1102    return ("FAILED");
[f12d199]1103  } else if (n->z_auth == ZAUTH_NO) {
[9381782]1104    return ("NO");
[f12d199]1105  } else if (n->z_auth == ZAUTH_YES) {
[9381782]1106    return ("YES");
1107  } else {
1108    return ("UNKNOWN");
[f12d199]1109  }           
[9381782]1110}
[09489b89]1111#else
[1077891a]1112const char *owl_zephyr_get_authstr(const void *n)
[09489b89]1113{
1114  return("");
1115}
1116#endif
[9381782]1117
[2de4f20]1118/* Returns a buffer of subscriptions or an error message.  Caller must
1119 * free the return.
[09489b89]1120 */
[c79a047]1121char *owl_zephyr_getsubs(void)
[09489b89]1122{
1123#ifdef HAVE_LIBZEPHYR
[c73a22d]1124  Code_t ret;
1125  int num, i, one;
[09489b89]1126  ZSubscription_t sub;
[df3a1f4]1127  GString *buf;
[09489b89]1128
[c73a22d]1129  ret = ZRetrieveSubscriptions(0, &num);
1130  if (ret != ZERR_NONE)
1131    return g_strdup_printf("Zephyr: Requesting subscriptions: %s\n", error_message(ret));
1132  if (num == 0)
1133    return g_strdup("Zephyr: No subscriptions retrieved\n");
[09489b89]1134
[df3a1f4]1135  buf = g_string_new("");
[09489b89]1136  for (i=0; i<num; i++) {
[df3a1f4]1137    one = 1;
[09489b89]1138    if ((ret = ZGetSubscriptions(&sub, &one)) != ZERR_NONE) {
1139      ZFlushSubscriptions();
[df3a1f4]1140      g_string_free(buf, true);
[c73a22d]1141      return g_strdup_printf("Zephyr: Getting subscriptions: %s\n", error_message(ret));
[09489b89]1142    } else {
[df3a1f4]1143      /* g_string_append_printf would be backwards. */
[3472845]1144      char *tmp = g_strdup_printf("<%s,%s,%s>\n",
1145                                  sub.zsub_class,
1146                                  sub.zsub_classinst,
1147                                  sub.zsub_recipient);
[df3a1f4]1148      g_string_prepend(buf, tmp);
[ddbbcffa]1149      g_free(tmp);
[09489b89]1150    }
1151  }
1152
1153  ZFlushSubscriptions();
[df3a1f4]1154  return g_string_free(buf, false);
[09489b89]1155#else
[d4927a7]1156  return(g_strdup("Zephyr not available"));
[09489b89]1157#endif
1158}
1159
[e19eb97]1160const char *owl_zephyr_get_variable(const char *var)
[09489b89]1161{
1162#ifdef HAVE_LIBZEPHYR
[712caac]1163  return(ZGetVariable(zstr(var)));
[09489b89]1164#else
1165  return("");
1166#endif
1167}
1168
[e19eb97]1169void owl_zephyr_set_locationinfo(const char *host, const char *val)
[09489b89]1170{
1171#ifdef HAVE_LIBZEPHYR
[712caac]1172  ZInitLocationInfo(zstr(host), zstr(val));
[09489b89]1173#endif
1174}
[f203cad]1175
1176const char *owl_zephyr_normalize_exposure(const char *exposure)
1177{
1178  if (exposure == NULL)
1179    return NULL;
1180#ifdef HAVE_LIBZEPHYR
1181  return ZParseExposureLevel(zstr(exposure));
1182#else
1183  return exposure;
1184#endif
1185}
1186
1187int owl_zephyr_set_default_exposure(const char *exposure)
1188{
1189#ifdef HAVE_LIBZEPHYR
1190  Code_t ret;
1191  if (exposure == NULL)
1192    return -1;
1193  exposure = ZParseExposureLevel(zstr(exposure));
1194  if (exposure == NULL)
1195    return -1;
1196  ret = ZSetVariable(zstr("exposure"), zstr(exposure)); /* ZSetVariable does file I/O */
1197  if (ret != ZERR_NONE) {
1198    owl_function_error("Unable to set default exposure location: %s", error_message(ret));
1199    return -1;
1200  }
1201#endif
1202  return 0;
1203}
1204
1205const char *owl_zephyr_get_default_exposure(void)
1206{
1207#ifdef HAVE_LIBZEPHYR
1208  const char *exposure = ZGetVariable(zstr("exposure")); /* ZGetVariable does file I/O */
1209  if (exposure == NULL)
1210    return EXPOSE_REALMVIS;
1211  exposure = ZParseExposureLevel(zstr(exposure));
1212  if (exposure == NULL) /* The user manually entered an invalid value in ~/.zephyr.vars, or something weird happened. */
1213    return EXPOSE_REALMVIS;
1214  return exposure;
1215#else
1216  return "";
1217#endif
1218}
1219
1220int owl_zephyr_set_exposure(const char *exposure)
1221{
1222#ifdef HAVE_LIBZEPHYR
1223  Code_t ret;
1224  if (exposure == NULL)
1225    return -1;
1226  exposure = ZParseExposureLevel(zstr(exposure));
1227  if (exposure == NULL)
1228    return -1;
1229  ret = ZSetLocation(zstr(exposure));
1230  if (ret != ZERR_NONE) {
1231    owl_function_error("Unable to set exposure level: %s.", error_message(ret));
1232    return -1;
1233  }
1234#endif
1235  return 0;
1236}
[09489b89]1237 
[e3d9c77]1238/* Strip a local realm fron the zephyr user name.
1239 * The caller must free the return
1240 */
[e19eb97]1241char *short_zuser(const char *in)
[e3d9c77]1242{
[5d56a27]1243  char *ptr = strrchr(in, '@');
1244  if (ptr && (ptr[1] == '\0' || !strcasecmp(ptr+1, owl_zephyr_get_realm()))) {
1245    return g_strndup(in, ptr - in);
[e3d9c77]1246  }
[5d56a27]1247  return g_strdup(in);
[e3d9c77]1248}
1249
1250/* Append a local realm to the zephyr user name if necessary.
1251 * The caller must free the return.
1252 */
[e19eb97]1253char *long_zuser(const char *in)
[e3d9c77]1254{
[5d56a27]1255  char *ptr = strrchr(in, '@');
1256  if (ptr) {
1257    if (ptr[1])
1258      return g_strdup(in);
1259    /* Ends in @, so assume default realm. */
1260    return g_strdup_printf("%s%s", in, owl_zephyr_get_realm());
[e3d9c77]1261  }
[5d56a27]1262  return g_strdup_printf("%s@%s", in, owl_zephyr_get_realm());
[e3d9c77]1263}
1264
[4e29ecb]1265/* Return the realm of the zephyr user name. Caller does /not/ free the return.
1266 * The string is valid at least as long as the input is.
1267 */
1268const char *zuser_realm(const char *in)
1269{
1270  char *ptr = strrchr(in, '@');
1271  /* If the name has an @ and does not end with @, use that. Otherwise, take
1272   * the default realm. */
1273  return (ptr && ptr[1]) ? (ptr+1) : owl_zephyr_get_realm();
1274}
1275
[e3d9c77]1276/* strip out the instance from a zsender's principal.  Preserves the
[9d21120]1277 * realm if present.  Leave host/ and daemon/ krb5 principals
1278 * alone. Also leave rcmd. and daemon. krb4 principals alone. The
1279 * caller must free the return.
[e3d9c77]1280 */
[e19eb97]1281char *owl_zephyr_smartstripped_user(const char *in)
[e3d9c77]1282{
[9d21120]1283  char *slash, *dot, *realm, *out;
[e3d9c77]1284
[d4927a7]1285  out = g_strdup(in);
[e3d9c77]1286
1287  /* bail immeaditly if we don't have to do any work */
[9d21120]1288  slash = strchr(out, '/');
1289  dot = strchr(out, '.');
1290  if (!slash && !dot) {
[e3d9c77]1291    return(out);
1292  }
[9d21120]1293
1294  if (!strncasecmp(out, OWL_ZEPHYR_NOSTRIP_HOST, strlen(OWL_ZEPHYR_NOSTRIP_HOST)) ||
1295      !strncasecmp(out, OWL_ZEPHYR_NOSTRIP_RCMD, strlen(OWL_ZEPHYR_NOSTRIP_RCMD)) ||
1296      !strncasecmp(out, OWL_ZEPHYR_NOSTRIP_DAEMON5, strlen(OWL_ZEPHYR_NOSTRIP_DAEMON5)) ||
1297      !strncasecmp(out, OWL_ZEPHYR_NOSTRIP_DAEMON4, strlen(OWL_ZEPHYR_NOSTRIP_DAEMON4))) {
[e3d9c77]1298    return(out);
1299  }
[9d21120]1300
1301  realm = strchr(out, '@');
1302  if (!slash && dot && realm && (dot > realm)) {
1303    /* There's no '/', and the first '.' is in the realm */
[e3d9c77]1304    return(out);
1305  }
1306
[fa4562c]1307  /* remove the realm from out, but hold on to it */
[e3d9c77]1308  if (realm) realm[0]='\0';
1309
1310  /* strip */
[9d21120]1311  if (slash) slash[0] = '\0';  /* krb5 style user/instance */
1312  else if (dot) dot[0] = '\0'; /* krb4 style user.instance */
[e3d9c77]1313
1314  /* reattach the realm if we had one */
1315  if (realm) {
1316    strcat(out, "@");
1317    strcat(out, realm+1);
1318  }
1319
1320  return(out);
1321}
[5a95b69]1322
1323/* read the list of users in 'filename' as a .anyone file, and put the
1324 * names of the zephyr users in the list 'in'.  If 'filename' is NULL,
1325 * use the default .anyone file in the users home directory.  Returns
1326 * -1 on failure, 0 on success.
1327 */
[e19eb97]1328int owl_zephyr_get_anyone_list(owl_list *in, const char *filename)
[5a95b69]1329{
1330#ifdef HAVE_LIBZEPHYR
[b7ee89b]1331  char *ourfile, *tmp, *s = NULL;
[5a95b69]1332  FILE *f;
1333
[6ea3890]1334  ourfile = owl_zephyr_dotfile(".anyone", filename);
[b7ee89b]1335
1336  f = fopen(ourfile, "r");
[5a95b69]1337  if (!f) {
1338    owl_function_error("Error opening file %s: %s", ourfile, strerror(errno) ? strerror(errno) : "");
[ddbbcffa]1339    g_free(ourfile);
[b7ee89b]1340    return -1;
[5a95b69]1341  }
[ddbbcffa]1342  g_free(ourfile);
[5a95b69]1343
[b7ee89b]1344  while (owl_getline_chomp(&s, f)) {
[5a95b69]1345    /* ignore comments, blank lines etc. */
[b7ee89b]1346    if (s[0] == '#' || s[0] == '\0')
1347      continue;
1348
1349    /* ignore from # on */
1350    tmp = strchr(s, '#');
1351    if (tmp)
1352      tmp[0] = '\0';
1353
1354    /* ignore from SPC */
1355    tmp = strchr(s, ' ');
1356    if (tmp)
1357      tmp[0] = '\0';
1358
1359    owl_list_append_element(in, long_zuser(s));
[5a95b69]1360  }
[ddbbcffa]1361  g_free(s);
[5a95b69]1362  fclose(f);
[b7ee89b]1363  return 0;
[5a95b69]1364#else
[b7ee89b]1365  return -1;
[5a95b69]1366#endif
1367}
[13a3c1db]1368
[f25812b]1369#ifdef HAVE_LIBZEPHYR
1370void owl_zephyr_process_pseudologin(ZNotice_t *n)
1371{
1372  owl_message *m;
1373  owl_zbuddylist *zbl;
1374  GList **zaldlist;
1375  GList *zaldptr;
1376  ZAsyncLocateData_t *zald = NULL;
1377  ZLocations_t location;
1378  int numlocs, ret, notify;
1379
1380  /* Find a ZALD to match this notice. */
1381  zaldlist = owl_global_get_zaldlist(&g);
1382  zaldptr = g_list_first(*zaldlist);
1383  while (zaldptr) {
1384    if (ZCompareALDPred(n, zaldptr->data)) {
1385      zald = zaldptr->data;
1386      *zaldlist = g_list_remove(*zaldlist, zaldptr->data);
1387      break;
1388    }
1389    zaldptr = g_list_next(zaldptr);
1390  }
1391  if (zald) {
1392    /* Deal with notice. */
1393    notify = owl_global_get_pseudologin_notify(&g);
1394    zbl = owl_global_get_zephyr_buddylist(&g);
1395    ret = ZParseLocations(n, zald, &numlocs, NULL);
1396    if (ret == ZERR_NONE) {
1397      if (numlocs > 0 && !owl_zbuddylist_contains_user(zbl, zald->user)) {
1398        if (notify) {
1399          numlocs = 1;
1400          ret = ZGetLocations(&location, &numlocs);
1401          if (ret == ZERR_NONE) {
1402            /* Send a PSEUDO LOGIN! */
[96828e4]1403            m = g_new(owl_message, 1);
[f25812b]1404            owl_message_create_pseudo_zlogin(m, 0, zald->user,
1405                                             location.host,
1406                                             location.time,
1407                                             location.tty);
1408            owl_global_messagequeue_addmsg(&g, m);
1409          }
1410          owl_zbuddylist_adduser(zbl, zald->user);
1411          owl_function_debugmsg("owl_function_zephyr_buddy_check: login for %s ", zald->user);
1412        }
1413      } else if (numlocs == 0 && owl_zbuddylist_contains_user(zbl, zald->user)) {
1414        /* Send a PSEUDO LOGOUT! */
1415        if (notify) {
[96828e4]1416          m = g_new(owl_message, 1);
[f25812b]1417          owl_message_create_pseudo_zlogin(m, 1, zald->user, "", "", "");
1418          owl_global_messagequeue_addmsg(&g, m);
1419        }
1420        owl_zbuddylist_deluser(zbl, zald->user);
1421        owl_function_debugmsg("owl_function_zephyr_buddy_check: logout for %s ", zald->user);
1422      }
1423    }
1424    ZFreeALD(zald);
[ddbbcffa]1425    g_free(zald);
[f25812b]1426  }
1427}
1428#else
1429void owl_zephyr_process_pseudologin(void *n)
1430{
1431}
1432#endif
1433
[3687413]1434void owl_zephyr_buddycheck_timer(owl_timer *t, void *data)
1435{
1436  if (owl_global_is_pseudologins(&g)) {
1437    owl_function_debugmsg("Doing zephyr buddy check");
1438    owl_function_zephyr_buddy_check(1);
1439  } else {
1440    owl_function_debugmsg("Warning: owl_zephyr_buddycheck_timer call pointless; timer should have been disabled");
1441  }
1442}
1443
[12e291a]1444/*
1445 * Process zephyrgrams from libzephyr's queue. To prevent starvation,
1446 * process a maximum of OWL_MAX_ZEPHYRGRAMS_TO_PROCESS.
1447 *
1448 * Returns the number of zephyrgrams processed.
1449 */
1450
1451#define OWL_MAX_ZEPHYRGRAMS_TO_PROCESS 20
1452
[b848e30]1453#ifdef HAVE_LIBZEPHYR
[e9c6fc8]1454static int _owl_zephyr_process_events(void)
[12e291a]1455{
[13a3c1db]1456  int zpendcount=0;
1457  ZNotice_t notice;
[8ab1f28]1458  Code_t code;
[13a3c1db]1459  owl_message *m=NULL;
1460
[12e291a]1461  while(owl_zephyr_zpending() && zpendcount < OWL_MAX_ZEPHYRGRAMS_TO_PROCESS) {
[13a3c1db]1462    if (owl_zephyr_zpending()) {
[8ab1f28]1463      if ((code = ZReceiveNotice(&notice, NULL)) != ZERR_NONE) {
1464        owl_function_debugmsg("Error: %s while calling ZReceiveNotice\n",
1465                              error_message(code));
1466        continue;
1467      }
[13a3c1db]1468      zpendcount++;
1469
1470      /* is this an ack from a zephyr we sent? */
1471      if (owl_zephyr_notice_is_ack(&notice)) {
1472        owl_zephyr_handle_ack(&notice);
[46c7f5b]1473        ZFreeNotice(&notice);
[13a3c1db]1474        continue;
1475      }
1476
1477      /* if it's a ping and we're not viewing pings then skip it */
1478      if (!owl_global_is_rxping(&g) && !strcasecmp(notice.z_opcode, "ping")) {
[46c7f5b]1479        ZFreeNotice(&notice);
[13a3c1db]1480        continue;
1481      }
1482
[f25812b]1483      /* if it is a LOCATE message, it's for pseudologins. */
1484      if (strcmp(notice.z_opcode, LOCATE_LOCATE) == 0) {
1485        owl_zephyr_process_pseudologin(&notice);
1486        ZFreeNotice(&notice);
1487        continue;
1488      }
1489
[13a3c1db]1490      /* create the new message */
[96828e4]1491      m=g_new(owl_message, 1);
[13a3c1db]1492      owl_message_create_from_znotice(m, &notice);
1493
1494      owl_global_messagequeue_addmsg(&g, m);
1495    }
1496  }
[12e291a]1497  return zpendcount;
[13a3c1db]1498}
1499
[959cb85]1500typedef struct { /*noproto*/
1501  GSource source;
1502  GPollFD poll_fd;
1503} owl_zephyr_event_source;
1504
1505static GSource *owl_zephyr_event_source_new(int fd) {
1506  GSource *source;
1507  owl_zephyr_event_source *event_source;
1508
1509  source = g_source_new(&zephyr_event_funcs, sizeof(owl_zephyr_event_source));
1510  event_source = (owl_zephyr_event_source*) source;
1511  event_source->poll_fd.fd = fd;
1512  event_source->poll_fd.events = G_IO_IN | G_IO_HUP | G_IO_PRI | G_IO_ERR;
1513  g_source_add_poll(source, &event_source->poll_fd);
1514
1515  return source;
[12e291a]1516}
1517
[959cb85]1518static gboolean owl_zephyr_event_prepare(GSource *source, int *timeout) {
1519  *timeout = -1;
1520  return owl_zephyr_zqlength() > 0;
1521}
1522
1523static gboolean owl_zephyr_event_check(GSource *source) {
1524  owl_zephyr_event_source *event_source = (owl_zephyr_event_source*)source;
1525  if (event_source->poll_fd.revents & event_source->poll_fd.events)
1526    return owl_zephyr_zpending() > 0;
1527  return FALSE;
1528}
1529
1530static gboolean owl_zephyr_event_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) {
1531  _owl_zephyr_process_events();
1532  return TRUE;
[13a3c1db]1533}
[b848e30]1534#endif
Note: See TracBrowser for help on using the repository browser.