/* kind = 0 for sent, 1 for toobig */ static void xmsg_unlink_dotfiles(session_t *s, const char *varname) { if (session_int_get(s, varname)) { const int kind = !xstrcasecmp(varname, "unlink_sent"); const int maxfs = session_int_get(s, "max_filesize"); const char *dfsuffix = session_get(s, "dotfile_suffix"); const char *dir = xmsg_dirfix(session_uid_get(s)+XMSG_UID_DIROFFSET); DIR *d; struct dirent *de; struct stat st, std; char *df, *dfd, *dp, *dpd; if (!dir || !(d = opendir(dir))) { xdebug("unable to open specified directory"); return; } df = xmalloc(xstrlen(dir) + NAME_MAX + 2); dfd = xmalloc(xstrlen(dir) + NAME_MAX + 3 + xstrlen(dfsuffix)); xstrcpy(df, dir); dp = df + xstrlen(df); *(dp++) = '/'; xstrcpy(dfd, df); dpd = dfd + xstrlen(dfd); *(dpd++) = '.'; while ((de = readdir(d))) { if (de->d_name[0] == '.') continue; if (xstrlen(de->d_name) > NAME_MAX) { xdebug2(DEBUG_ERROR, "Filename longer than NAME_MAX (%s), skipping.", de->d_name); continue; } xstrcpy(dp, de->d_name); xstrcpy(dpd, de->d_name); xstrcat(dpd, dfsuffix); if (!stat(df, &st) && !stat(dfd, &std) && ((!maxfs || (st.st_size < maxfs)) == kind)) { xdebug("removing %s", de->d_name); unlink(df); unlink(dfd); } } closedir(d); xfree(df); xfree(dfd); } }
static WATCHER(xmsg_handle_data) { int n; int c = 0; struct inotify_event *evp; if (type) return -1; ioctl(fd, FIONREAD, &n); if (n == 0) return 0; ev = xrealloc(ev, n); n = read(fd, ev, n); if (n < 0) xerrn("inotify read() failed"); for (evp = ev; n > 0; n -= (evp->len + sizeof(struct inotify_event)), evp = (void*) evp + (evp->len + sizeof(struct inotify_event))) { session_t *s; for (s = sessions; s; s = s->next) { if (s && (s->priv == (void*) (long int) evp->wd) && (s->plugin == &xmsg_plugin)) break; } xdebug("n = %d, wd = %d, str = %s", n, evp->wd, evp->name); if ((evp->mask & IN_IGNORED) || !s || !session_connected_get(s)) continue; else if (evp->mask & IN_UNMOUNT) xmsg_disconnect(NULL, NULL, s, NULL, -1); else if (!(evp->mask & IN_Q_OVERFLOW) && (c != -1) && (!xmsg_handle_file(s, evp->name))) c++; if ((evp->mask & IN_Q_OVERFLOW) || ((config_maxinotifycount > 0) && c >= config_maxinotifycount)) { for (s = sessions; s; s = s->next) { if (s && (s->plugin == &xmsg_plugin)) { const int i = session_int_get(s, "oneshot_resume_timer"); if (!timer_remove_session(s, "o")) xdebug("old oneshot resume timer removed"); if ((i > 0) && timer_add_session(s, "o", i, 0, xmsg_iterate_dir)) { xdebug("oneshot resume timer added"); session_status_set(s, EKG_STATUS_AWAY); } else session_status_set(s, EKG_STATUS_AVAIL); c = -1; } } } } if (c >= 0) xdebug("processed %d files", c); else xdebug("reached max_inotifycount"); return 0; }
void ekg_loop() { g_main_context_iteration(NULL, FALSE); { #ifdef WATCHES_FIXME { /* przejrzyj deskryptory */ list_t l; for (l = watches; l; l = l->next) { watch_t *w = l->data; if (!w) continue; if (!FD_ISSET(w->fd, &rd) && !FD_ISSET(w->fd, &wd)) { /* timeout checking */ if (w->timeout < 1 || (tv.tv_sec - w->started) < w->timeout) continue; w->removed = -1; if (w->buf) { int (*handler)(int, int, char*, void*) = w->handler; if (handler(2, w->fd, NULL, w->data) == -1 || w->removed == 1) { w->removed = 0; watch_free(w); continue; } } else { int (*handler)(int, int, int, void*) = w->handler; if (handler(2, w->fd, w->type, w->data) == -1 || w->removed == 1) { w->removed = 0; watch_free(w); continue; } } w->removed = 0; continue; } if (w->fd == 0) { session_t *s; for (s = sessions; s; s = s->next) { if (!s->connected || !s->autoaway) continue; if (session_int_get(s, "auto_back") == 2) command_exec(NULL, s, ("/_autoback"), 2); } } } } #endif } #undef tv return; }
int irc_autorejoin(session_t *s, int when, char *chan) { irc_private_t *j; string_t st; window_t *w; char *chanprefix; int rejoin; #if 1 /* there's no need of doing it, already checked by irc_onkick_handler() or if it goes through irc_c_init() it's even better. */ if (!s || !(j = s->priv) || (s->plugin != &irc_plugin)) return -1; #endif chanprefix = SOP(_005_CHANTYPES); rejoin = session_int_get(s, "REJOIN"); if (!(rejoin&(1<<(when)))) return -1; switch (when) { case IRC_REJOIN_CONNECT: st = string_init(NULL); for (w = windows; w; w = w->next) { if (!w->target || w->session != s) /* check if sessions match and has w->target */ continue; if (valid_plugin_uid(s->plugin, w->target) != 1) /* check if window is correct for irc: */ continue; if (!xstrchr(chanprefix, (w->target)[4])) /* check if this is channel.. */ continue; if (st->len) string_append_c(st, ','); if ((w->target)[4] == '!') { string_append_c(st, '!'); string_append(st, w->target + 10); } else { string_append(st, w->target + 4); } } if (st->len) irc_write(s, "JOIN %s\r\n", st->str); string_free(st, 1); break; case IRC_REJOIN_KICK: irc_write(s, "JOIN %s\r\n", chan); break; default: return -1; } return 0; }
static void xmsg_timer_change(session_t *s, const char *varname) { int n = (varname ? session_int_get(s, varname) : 0); xdebug("n = %d", n); if (!varname || session_connected_get(s)) { if (!timer_remove_session(s, "w")) xdebug("old timer removed"); if (n > 0) { if (timer_add_session(s, "w", n, 1, xmsg_iterate_dir)) xdebug("new timer added"); } } }
/** * ekg_autoaway_timer() * * * less important things which don't need to be checked every main loop iteration * e.g. autoaways * * executed each second. */ static TIMER(ekg_autoaway_timer) { session_t *sl; time_t t; if (type) return 0; t = time(NULL); /* sprawd¼ autoawaye ró¿nych sesji */ for (sl = sessions; sl; sl = sl->next) { session_t *s = sl; int tmp; if (!s->connected || (s->status < EKG_STATUS_AWAY)) /* lowest autostatus is autoxa, so from xa and lower ones we can't go further */ continue; do { if ((s->status == EKG_STATUS_AWAY) || (tmp = session_int_get(s, "auto_away")) < 1 || !s->activity) break; if (t - s->activity > tmp) command_exec(NULL, s, ("/_autoaway"), 0); } while (0); do { if ((tmp = session_int_get(s, "auto_xa")) < 1 || !s->activity) break; if (t - s->activity > tmp) command_exec(NULL, s, ("/_autoxa"), 0); } while (0); } return 0; }
static TIMER_SESSION(xmsg_iterate_dir) { const char *dir; DIR *d; struct dirent *de; int n = 0; const int maxn = session_int_get(s, "max_oneshot_files"); if (type || !s || !session_connected_get(s)) return -1; session_status_set(s, EKG_STATUS_AVAIL); if (!(dir = xmsg_dirfix(session_uid_get(s)+XMSG_UID_DIROFFSET)) || !(d = opendir(dir))) { xerr("unable to open specified directory"); return 0; } while ((de = readdir(d))) { if (!xmsg_handle_file(s, de->d_name)) n++; if ((maxn > 0) && n >= maxn) { const int i = session_int_get(s, "oneshot_resume_timer"); if ((i > 0) && timer_add_session(s, "o", i, 0, xmsg_iterate_dir)) xdebug("oneshot resume timer added"); session_status_set(s, EKG_STATUS_AWAY); break; } } closedir(d); xdebug("processed %d files", n); return 0; }
static int xmsg_handle_file(session_t *s, const char *fn) { const int nounlink = !session_int_get(s, "unlink_sent"); const int utb = session_int_get(s, "unlink_toobig"); const int maxfs = session_int_get(s, "max_filesize"); const char *dfsuffix = session_get(s, "dotfile_suffix"); char *namesep = (char*) session_get(s, "name_separator"); char *dir; int dirlen; char *msg = NULL; int err, fs; time_t ft = 0; if (*fn == '.') /* we're skipping ALL dotfiles */ return -1; dir = (char*) xmsg_dirfix(session_uid_get(s)+XMSG_UID_DIROFFSET); dirlen = xstrlen(dir); /* first check if buffer is long enough to fit the whole path for dotfile */ if (strlcpy(dir+dirlen+1, fn, PATH_MAX-dirlen-2-xstrlen(dfsuffix)) >= PATH_MAX-dirlen-2-xstrlen(dfsuffix)) xerr("Buffer too small for: fn = %s, len(fn) = %d, dirlen = %d, dfsuffixlen = %d", fn, xstrlen(fn), dirlen, xstrlen(dfsuffix)); /* then fill in middle part of path */ dir[dirlen] = '/'; /* and take a much closer look the file */ xdebug("s = %s, d = %s, fn = %s", session_uid_get(s), dir, fn); if ((err = xmsg_checkoutfile(dir, &msg, &fs, &ft, maxfs))) { if (err == EFBIG) { print((utb ? "xmsg_toobigrm" : "xmsg_toobig"), fn, session_name(s)); if (utb) { unlink(dir); return -1; } /* else we need to create the dotfile first */ } else if (err != ENOENT && err != EINVAL) return -1; } else if (!nounlink && (utb == (err == EFBIG))) unlink(dir); /* here: dir = dotf */ memmove(dir+dirlen+2, dir+dirlen+1, xstrlen(dir) - dirlen); dir[dirlen+1] = '.'; xstrcpy(dir+xstrlen(dir), dfsuffix); /* we've already checked whether it fits */ { struct stat st; int r; if (nounlink || !utb) { r = !(stat(dir, &st) || S_ISDIR(st.st_mode)); } else r = 0; if (err == ENOENT) { if (r) /* clean up stale dotfile */ unlink(dir); xfree(msg); return -1; } else if (r) { xfree(msg); /* XXX: I think that we rather shouldn't first read, then check if it is needed, at least for nounlink mode */ return -1; } else if ((nounlink && !(utb && err == EFBIG)) || (!utb && err == EFBIG)) close(open(dir, O_WRONLY|O_CREAT|O_TRUNC|O_NOFOLLOW, 0600)); } if (err == EFBIG) return -1; else if (err == EINVAL) xdebug("empty file, not submitting"); else { char *uid = xmalloc(strlen(fn) + 6); char *msgx = NULL; { const char *charset = session_get(s, "charset"); if (charset && (msgx = ekg_convert_string(msg, charset, NULL))) xfree(msg); else msgx = msg; } xstrcpy(uid, "xmsg:"); xstrcat(uid, fn); if (namesep) { char *p, *q = NULL; for (p = namesep; *p; p++) { char *r = xstrrchr(uid+XMSG_UID_DIROFFSET, *p); if (r > q) q = r; } if (q) *q = '\0'; } protocol_message_emit(s, uid, NULL, msgx, NULL, ft, EKG_MSGCLASS_CHAT, NULL, EKG_TRY_BEEP, 0); xfree(msgx); xfree(uid); } return 0; }