source: zephyr.c @ 074bdaa

release-1.10release-1.8release-1.9
Last change on this file since 074bdaa was 72146c7, checked in by David Benjamin <davidben@mit.edu>, 13 years ago
Convert pseudologins timer to glib timers
  • 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
[72146c7]1434gboolean owl_zephyr_buddycheck_timer(void *data)
[3687413]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  }
[72146c7]1442  return TRUE;
[3687413]1443}
1444
[12e291a]1445/*
1446 * Process zephyrgrams from libzephyr's queue. To prevent starvation,
1447 * process a maximum of OWL_MAX_ZEPHYRGRAMS_TO_PROCESS.
1448 *
1449 * Returns the number of zephyrgrams processed.
1450 */
1451
1452#define OWL_MAX_ZEPHYRGRAMS_TO_PROCESS 20
1453
[b848e30]1454#ifdef HAVE_LIBZEPHYR
[e9c6fc8]1455static int _owl_zephyr_process_events(void)
[12e291a]1456{
[13a3c1db]1457  int zpendcount=0;
1458  ZNotice_t notice;
[8ab1f28]1459  Code_t code;
[13a3c1db]1460  owl_message *m=NULL;
1461
[12e291a]1462  while(owl_zephyr_zpending() && zpendcount < OWL_MAX_ZEPHYRGRAMS_TO_PROCESS) {
[13a3c1db]1463    if (owl_zephyr_zpending()) {
[8ab1f28]1464      if ((code = ZReceiveNotice(&notice, NULL)) != ZERR_NONE) {
1465        owl_function_debugmsg("Error: %s while calling ZReceiveNotice\n",
1466                              error_message(code));
1467        continue;
1468      }
[13a3c1db]1469      zpendcount++;
1470
1471      /* is this an ack from a zephyr we sent? */
1472      if (owl_zephyr_notice_is_ack(&notice)) {
1473        owl_zephyr_handle_ack(&notice);
[46c7f5b]1474        ZFreeNotice(&notice);
[13a3c1db]1475        continue;
1476      }
1477
1478      /* if it's a ping and we're not viewing pings then skip it */
1479      if (!owl_global_is_rxping(&g) && !strcasecmp(notice.z_opcode, "ping")) {
[46c7f5b]1480        ZFreeNotice(&notice);
[13a3c1db]1481        continue;
1482      }
1483
[f25812b]1484      /* if it is a LOCATE message, it's for pseudologins. */
1485      if (strcmp(notice.z_opcode, LOCATE_LOCATE) == 0) {
1486        owl_zephyr_process_pseudologin(&notice);
1487        ZFreeNotice(&notice);
1488        continue;
1489      }
1490
[13a3c1db]1491      /* create the new message */
[96828e4]1492      m=g_new(owl_message, 1);
[13a3c1db]1493      owl_message_create_from_znotice(m, &notice);
1494
1495      owl_global_messagequeue_addmsg(&g, m);
1496    }
1497  }
[12e291a]1498  return zpendcount;
[13a3c1db]1499}
1500
[959cb85]1501typedef struct { /*noproto*/
1502  GSource source;
1503  GPollFD poll_fd;
1504} owl_zephyr_event_source;
1505
1506static GSource *owl_zephyr_event_source_new(int fd) {
1507  GSource *source;
1508  owl_zephyr_event_source *event_source;
1509
1510  source = g_source_new(&zephyr_event_funcs, sizeof(owl_zephyr_event_source));
1511  event_source = (owl_zephyr_event_source*) source;
1512  event_source->poll_fd.fd = fd;
1513  event_source->poll_fd.events = G_IO_IN | G_IO_HUP | G_IO_PRI | G_IO_ERR;
1514  g_source_add_poll(source, &event_source->poll_fd);
1515
1516  return source;
[12e291a]1517}
1518
[959cb85]1519static gboolean owl_zephyr_event_prepare(GSource *source, int *timeout) {
1520  *timeout = -1;
1521  return owl_zephyr_zqlength() > 0;
1522}
1523
1524static gboolean owl_zephyr_event_check(GSource *source) {
1525  owl_zephyr_event_source *event_source = (owl_zephyr_event_source*)source;
1526  if (event_source->poll_fd.revents & event_source->poll_fd.events)
1527    return owl_zephyr_zpending() > 0;
1528  return FALSE;
1529}
1530
1531static gboolean owl_zephyr_event_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) {
1532  _owl_zephyr_process_events();
1533  return TRUE;
[13a3c1db]1534}
[b848e30]1535#endif
Note: See TracBrowser for help on using the repository browser.