irctk

libircclient binding for scripts
git clone https://a3nm.net/git/irctk/
Log | Files | Refs | README

commit 1969331400e4c56373c16ec5cfcbd9aaceb069a8
parent a8f47feea9525af8d8e402f83443d6b74f155b20
Author: Antoine Amarilli <a3nm@a3nm.net>
Date:   Mon, 18 Jun 2012 14:52:07 +0200

work on fifo_set, doesnotwork

Diffstat:
TODO | 7+++++++
irctk.c | 612+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
2 files changed, 434 insertions(+), 185 deletions(-)

diff --git a/TODO b/TODO @@ -1,5 +1,12 @@ +debug cat fifo | while read l; do seq 3; done | ./irctk -Fvfr 127.0.0.1 \#test > fifo +maybe debug fifo_set separately + http://www.iagora.com/~espel/sirc/sirc.html handle nick following ssl support password support exit when killed, advertising the signal +use notices and errors +si on est full unbuffered, attendre qu'un write sur stdout ait fini de +bloquer avant de considérer que le write a été vu pour last_nick et autres +sinon, vérifier que le delimit par lignes vides est opérationnel diff --git a/irctk.c b/irctk.c @@ -32,6 +32,8 @@ enum event_tos {NOTHING, COMMAND, MESSAGE}; #define MAX_NICK_LEN 4096 #define LINE_BUFFER 4096 +#define INITIAL_CHAN_ALLOC 2 + #define max(a, b) ((b) > (a) ? (b) : (a)) const char *argp_program_version = "irctk 0.1"; @@ -165,7 +167,7 @@ struct arguments int port; char *password; char **channels; - int n_channels; + int n_channels; // TODO reconcile this with fifos int verbosity; @@ -449,20 +451,78 @@ void debug_args() typedef struct line { - char* line; - char last_chan_in[MAX_LEN]; - char last_chans_out[MAX_LEN]; - char last_nick_in[MAX_LEN]; + char *line; + char *full_line; + struct line* next_dep; + char is_head; + char is_sendable; } line; +typedef struct action { + char *line; + char *full_line; + char *destination; +} action; + typedef struct fifo { int hd; int tl; line queue[LINE_BUFFER]; +} fifo; + +typedef struct fifo_ctrl { pthread_cond_t empty; pthread_cond_t full; pthread_mutex_t mutex; -} fifo; +} fifo_ctrl; + +typedef struct fifo_set { + int n; + int allocated; + fifo_ctrl ctrl; + fifo *fifos; + char **chans; + char *was_pushed; +} fifo_set; + +void init_fifo_ctrl(fifo_ctrl *c) { + assert(!pthread_cond_init(&(c->empty), NULL)); + assert(!pthread_cond_init(&(c->full), NULL)); + assert(!pthread_mutex_init(&(c->mutex), NULL)); +} + +void init_fifo_set (fifo_set *s) { + s->n = 0; + s->allocated = INITIAL_CHAN_ALLOC; + s->chans = malloc(s->allocated * sizeof(char*)); + assert(s->chans); + s->fifos = malloc(s->allocated * sizeof(fifo)); + assert(s->fifos); + s->was_pushed = malloc(s->allocated * sizeof(char)); + assert(s->was_pushed); + init_fifo_ctrl(&(s->ctrl)); +} + +void destroy_fifo_ctrl(fifo_ctrl *f) { + pthread_cond_destroy(&f->empty); + pthread_cond_destroy(&f->full); + pthread_mutex_destroy(&f->mutex); +} + +void destroy_fifo_set (fifo_set *s) { + int i; + free(s->fifos); + for (i = 0; i < s->n ; i++) + free(s->chans[i]); + free(s->chans); + free(s->was_pushed); + destroy_fifo_ctrl(&(s->ctrl)); +} + +void init_fifo(fifo *f) { + f->hd = 0; + f->tl = 0; +} int size(fifo *f) { return (f->tl - f->hd + LINE_BUFFER) % LINE_BUFFER; @@ -470,84 +530,282 @@ int size(fifo *f) { int full(fifo *f) { return size(f) == LINE_BUFFER - 1; } +int full_fifo_set(fifo_set *s) { + // fifo_set is full if one fifo is full + int i; + for (i=0; i<s->n; i++) + if (full(&(s->fifos[i]))) + return 1; + return 0; +} int empty(fifo *f) { return size(f) == 0; } +int empty_fifo_set(fifo_set *s) { + // fifo_set is empty if all fifos are empty + int i; + for (i=0; i<s->n; i++) + if (!empty(&(s->fifos[i]))) + return 0; + return 1; +} -line pop(fifo *f) { - line result; - int was_full; - pthread_mutex_lock(&f->mutex); - debug("am popping, hd %d tl %d size %d", f->hd, f->tl, size(f)); - while (empty(f)) { - debug("wait nonempty"); - pthread_cond_wait(&f->empty, &f->mutex); +// line pop(fifo *f, fifo_ctrl *c) { +// line result; +// int was_full; +// pthread_mutex_lock(&c->mutex); +// debug("am popping, hd %d tl %d size %d", f->hd, f->tl, size(f)); +// while (empty(f)) { +// debug("wait nonempty"); +// pthread_cond_wait(&c->empty, &c->mutex); +// } +// debug("nonempty"); +// // now fifo isn't empty +// was_full = full(f); +// result = f->queue[f->hd]; +// debug("state POP 0:%s 1:%s 2:%s 3:%s 4:%s\n", +// f->queue[0].line, +// f->queue[1].line, +// f->queue[2].line, +// f->queue[3].line, +// f->queue[4].line +// ); +// debug("popped %s at %d", result.line, f->hd); +// f->hd++; +// f->hd %= LINE_BUFFER; +// if (was_full) +// pthread_cond_signal(&c->full); +// pthread_mutex_unlock(&c->mutex); +// return result; +// } +// +// void push(fifo *f, fifo_ctrl *c, char *fl, char *dest, char *l) { +// int was_empty; +// pthread_mutex_lock(&c->mutex); +// debug("am pushing, hd %d tl %d size %d", f->hd, f->tl, size(f)); +// while (full(f)) +// pthread_cond_wait(&c->full, &c->mutex); +// // now fifo isn't full +// was_empty = empty(f); +// f->queue[f->tl].line = l; +// f->queue[f->tl].full_line = fl; +// debug("pushed %s at %d\n", l, f->tl); +// debug("state PUSH 0:%s 1:%s 2:%s 3:%s 4:%s\n", +// f->queue[0].line, +// f->queue[1].line, +// f->queue[2].line, +// f->queue[3].line, +// f->queue[4].line +// ); +// f->tl++; +// f->tl %= LINE_BUFFER; +// if (was_empty) +// pthread_cond_signal(&c->empty); +// pthread_mutex_unlock(&c->mutex); +// } + +void realloc_chans(fifo_set *s) { + s->allocated *= 2; + assert(!realloc(s->chans, s->allocated*sizeof(char*))); + assert(!realloc(s->was_pushed, s->allocated*sizeof(char*))); + assert(!realloc(s->fifos, s->allocated*sizeof(fifo*))); +} + +int push_chan(fifo_set *s, char *chan) { + if (s->n == s->allocated) + realloc_chans(s); + s->chans[s->n] = malloc(MAX_LEN * sizeof(chan)); + assert(s->chans[s->n]); + strncpy(s->chans[s->n], chan, MAX_LEN-1); + init_fifo(&s->fifos[s->n]); + s->was_pushed[s->n] = 0; + return (s->n)++; +} + +int index_of_chan(fifo_set *s, char *chan) { + int i; + debug("asking for ioc for <%s>", chan); + for (i=0; i<s->n; i++) { + debug("compare to %d of %d value %s", i, s->n, s->chans[i]); + if (!strcmp(s->chans[i], chan)) { + debug("found ioc %d", i); + return i; + } } - debug("nonempty"); - // now fifo isn't empty - was_full = full(f); - result = f->queue[f->hd]; - /*debug("state 0:%s 1:%s 2:%s 3:%s 4:%s\n", - f->queue[0].line, - f->queue[1].line, - f->queue[2].line, - f->queue[3].line, - f->queue[4].line - );*/ - debug("popped %s at %d", result.line, f->hd); - f->hd++; - f->hd %= LINE_BUFFER; - if (was_full) - pthread_cond_signal(&f->full); - pthread_mutex_unlock(&f->mutex); - return result; + debug("must push"); + return push_chan(s, chan); } -void push(fifo *f, char* l, char* li, char* lni, char* lo) { - int was_empty; - pthread_mutex_lock(&f->mutex); - while (full(f)) - pthread_cond_wait(&f->full, &f->mutex); - // now fifo isn't full - was_empty = empty(f); + +line *push_one(fifo_set *s, char *fl, char *dest, char *l, line *last_ptr) { + int c = index_of_chan(s, dest); + debug("push_one %s %p ioc %d", fl, last_ptr, c); + fifo *f = &(s->fifos[c]); + line *result = &f->queue[f->tl]; + if (s->was_pushed[c]) + return last_ptr; // already pushed + s->was_pushed[c] = 1; f->queue[f->tl].line = l; - strncpy(f->queue[f->tl].last_chan_in, li, MAX_LEN-1); - strncpy(f->queue[f->tl].last_nick_in, lni, MAX_LEN-1); - strncpy(f->queue[f->tl].last_chans_out, lo, MAX_LEN-1); - debug("pushed %s at %d\n", l, f->tl); - /*debug("state 0:%s 1:%s 2:%s 3:%s 4:%s\n", - f->queue[0].line, - f->queue[1].line, - f->queue[2].line, - f->queue[3].line, - f->queue[4].line - );*/ + f->queue[f->tl].full_line = fl; + f->queue[f->tl].next_dep = last_ptr; + f->queue[f->tl].is_head = 0; + f->queue[f->tl].is_sendable = 0; f->tl++; f->tl %= LINE_BUFFER; - if (was_empty) - pthread_cond_signal(&f->empty); - pthread_mutex_unlock(&f->mutex); + return result; } -void init(fifo *f) { - f->hd = 0; - f->tl = 0; - assert(!pthread_cond_init(&f->empty, NULL)); - assert(!pthread_cond_init(&f->full, NULL)); - assert(!pthread_mutex_init(&f->mutex, NULL)); +void set_last_ptr(fifo_set *s, char *chan, line *ptr) { + int c = index_of_chan(s, chan); + fifo *f = &(s->fifos[c]); + debug("set_last_ptr %p for %s ioc %d", ptr, f->queue[f->tl - 1 + LINE_BUFFER % LINE_BUFFER].full_line, c); + f->queue[f->tl - 1 + LINE_BUFFER % LINE_BUFFER].next_dep = ptr; } -void destroy(fifo *f) { - pthread_cond_destroy(&f->empty); - pthread_cond_destroy(&f->full); - pthread_mutex_destroy(&f->mutex); +void reset_chan_marks(fifo_set *s) { + int i; + for (i=0; i<s->n; i++) + s->was_pushed[i] = 0; +} + +void push_fifo_set(fifo_set *s, char *fl, char *dests, char *l) { + debug("push_fifo_set %s", fl); + int was_empty; + pthread_mutex_lock(&s->ctrl.mutex); + while (full_fifo_set(s)) + pthread_cond_wait(&s->ctrl.full, &s->ctrl.mutex); + // now fifo_set isn't full + + int i = 0; + int cont = 1; + char *last_dest, *first_dest; + line *last_ptr = 0, *first_ptr = 0; + + last_dest = dests; + + reset_chan_marks(s); + was_empty = empty_fifo_set(s); + while (cont) + { + if (dests[i] == ',' || !dests[i]) + { + if (!dests[i]) + cont = 0; + if (i) + dests[i] = 0; + // only put the full line for *one* occurrence + last_ptr = push_one(s, !first_ptr?fl:NULL, last_dest, l, last_ptr); + assert(!cont); + if (!first_ptr) { + first_ptr = last_ptr; + first_dest = last_dest; + debug("first_ptr is %p full line %s, first_dest is %s", first_ptr, + first_ptr->full_line, first_dest); + } + last_dest = dests + i + 1; + } + i++; + } + debug("first_ptr is %p full line %s, first_dest is %s", first_ptr, + first_ptr->full_line, first_dest); + set_last_ptr(s, first_dest, first_ptr); + + if (was_empty) { + debug("signal for empty"); + pthread_cond_signal(&s->ctrl.empty); + } + pthread_mutex_unlock(&s->ctrl.mutex); +} + +void mark_head(fifo *f) { + f->queue[f->hd].is_head = 1; + f->queue[f->hd].is_sendable = 0; +} + +void mark_heads(fifo_set *s) { + int i; + for (i=0; i<s->n; i++) + mark_head(&s->fifos[i]); +} + +int mark_sendable_line(line *l) { + if (!l->is_head) + return 0; + if (l->is_sendable) + return 1; + l->is_sendable = 1; + // TODO TODO TODO lift this when we have real deps + debug("i am %p depending on %p", l, l->next_dep); + assert(l->next_dep == l); + return mark_sendable_line(l->next_dep); +} +int mark_sendable(fifo *f) { + return mark_sendable_line(&f->queue[f->hd]); +} +void unmark_sendable_line(line *l) { + if (!l->is_sendable) + return; + l->is_sendable = 0; + unmark_sendable_line(l->next_dep); +} +void unmark_sendable(fifo *f) { + unmark_sendable_line(&f->queue[f->hd]); +} +void pop_if_sendable(fifo_set *s, int c, int *n_result, action *result) { + fifo *f = &s->fifos[c]; + // don't push sentinel + if (f->queue[f->hd].is_sendable && f->queue[f->hd].line) { + result[*n_result].line = f->queue[f->hd].line; + result[*n_result].full_line = f->queue[f->hd].full_line; + result[*n_result].destination = s->chans[c]; + (*n_result)++; + f->hd++; + f->hd %= LINE_BUFFER; + } +} + +int pop_fifo_set(fifo_set *s, action **result) { + int n_result = 0; + int was_full; + int i; + pthread_mutex_lock(&s->ctrl.mutex); + while (empty_fifo_set(s)) { + debug("wait because empty"); + pthread_cond_wait(&s->ctrl.empty, &s->ctrl.mutex); + } + // now fifo isn't empty + debug("now fifo isn't empty"); + was_full = full_fifo_set(s); + mark_heads(s); + for (i=0; i<s->n; i++) { + debug("doing fifo for chan %s", s->chans[i]); + debug("fifo hd %d tl %d", s->fifos[i].hd, s->fifos[i].tl); + if (!mark_sendable(&s->fifos[i])) + unmark_sendable(&s->fifos[i]); + } + // freeing result is responsibility of callee + *result = malloc(s->n * sizeof(line)); + assert(*result); + for (i=0; i<s->n; i++) + pop_if_sendable(s, i, &n_result, *result); + if (!n_result) { + // only thing left is sentinel, return sentinel + n_result = 1; + result[0]->line = NULL; + result[0]->full_line = NULL; + } + debug("prepared %d results to return", n_result); + if (was_full) + pthread_cond_signal(&s->ctrl.full); + pthread_mutex_unlock(&s->ctrl.mutex); + return n_result; } // fifo for input // we want to read lines at the time we get them even if we are delaying writes // on the irc channel /* TODO fifo_out for output to avoid blocking if stdout blocks */ -fifo fifo_in; +fifo_set fifos; /* Our main chan is either the first CLI chan or our own chan if there are no @@ -650,89 +908,56 @@ int do_cmd_msg(irc_session_t *s, char* chan, char* line) return 0; } -// Send a message or do a command, possibly to multiple chans -int cmd_msg_chan(irc_session_t *s, char *target, char* line) -{ - int i = 0; - int cont = 1; - char tmp; - char *one_target; - int rsl = 0; - - debug("cmd_msg_chan %s %s\n", target, line); - one_target = target; - - while (cont) - { - if (target[i] == ',' || !target[i]) - { - if (!target[i]) - cont = 0; - tmp = target[i]; - target[i] = 0; - // return value is the max of seen return values, ie. some kind of "or" - rsl = max(rsl, do_cmd_msg(s, one_target, line)); - target[i] = tmp; - one_target = target + i + 1; - } - i++; - } - - return rsl; -} - // Handle a command request which might not specify a destination -int cmd_msg(irc_session_t *s, char* target, line l) +void cmd_msg(char *full_line, char *target, char *line) { int i = 0; - int ret; char *msg[2*MAX_LEN+2]; - debug("cmd_msg %s %s, last_in %s", target, l.line, l.last_chan_in); + debug("cmd_msg %s %s, last_in %s", target, line, args.last_chan_in); /* Manage the fact that target may be "" */ - if (!target[0]) - { - switch(args.default_destination) - { + if (!target[0]) { + debug("have to infer destination\n"); + switch(args.default_destination) { case DEFAULT_FIRST: - return cmd_msg_chan(s, first_chan(), l.line); + push_fifo_set(&fifos, full_line, first_chan(), line); + return; case DEFAULT_LAST_IN: - if (args.show_nick_prefix && l.last_nick_in[0] - && l.last_chan_in[0] == '#') - { - if (l.line[0] != '\n') - { + if (args.show_nick_prefix && args.last_nick_in[0] + && args.last_chan_in[0] == '#') { + if (line[0] != '\n') { msg[0] = 0; - strncat((char*) msg, l.last_nick_in, MAX_LEN-1); + strncat((char*) msg, args.last_nick_in, MAX_LEN-1); strcat((char*) msg, ": "); - strncat((char*) msg, l.line, MAX_LEN-1); - l.line = (char*) msg; + strncat((char*) msg, line, MAX_LEN-1); + line = (char*) msg; } else { - l.last_nick_in[0] = 0; + args.last_nick_in[0] = 0; } } - debug("will cmd_msg_chan %s %s\n", l.last_chan_in, l.line); - return cmd_msg_chan(s, l.last_chan_in, l.line); + debug("last_chan_in is %s", args.last_chan_in); + return push_fifo_set(&fifos, full_line, + args.last_chan_in[0] ? args.last_chan_in : first_chan(), line); case DEFAULT_LAST_OUT: - return cmd_msg_chan(s, l.last_chans_out, l.line); + return push_fifo_set(&fifos, full_line, + args.last_chans_out[0] ? args.last_chans_out : first_chan(), line); case DEFAULT_ALL: //TODO also for chans joined at runtime //TODO2: ugly, could have generated the comma-separated string //like for last_chans_out! for (i = 0; i < args.n_channels; i++) - ret = max(ret, cmd_msg_chan(s, args.channels[i], l.line)); + push_fifo_set(&fifos, full_line, args.channels[i], line); /* TODO return value */ - return ret; default: - return 42; // won't happen + return; // won't happen } } else { - return cmd_msg_chan(s, target, l.line); + push_fifo_set(&fifos, full_line, target, line); } } @@ -740,7 +965,6 @@ int cmd_msg(irc_session_t *s, char* target, line l) void manage_event (irc_session_t *session, const char *event, const char *origin, const char **params, unsigned int count) { - int cnt = 0; int rsl; // TODO use if (atoi(event) == LIBIRC_RFC_ERR_ERRONEUSNICKNAME) @@ -778,8 +1002,14 @@ void manage_event (irc_session_t *session, const char *event, const char *origin info("Cannot join channel: channel is invite-only."); } - debug("Event \"%s\", origin: \"%s\", params: %d", event, - origin ? origin : "NULL", cnt); + if (count == 2) { + debug("%s %s: %s %s\n", origin, event, params[0], params[1]); + } else if (count == 1) { + debug("%s %s: %s\n", origin, event, params[0]); + } else { + debug("Event \"%s\", origin: \"%s\", params: %d", event, + origin ? origin : "NULL", count); + } } // Handle a nick event @@ -895,9 +1125,12 @@ void event_channel (irc_session_t *session, const char *event, if (strcmp(params[0], args.nick)) { for (i=0; i<strlen(args.nick); i++) - if (args.nick[i] != params[1][i] || !params[1][i]) + if (args.nick[i] != params[1][i] || !params[1][i]) { ok = 0; - /* TODO test if ',' or ':' to avoid prefix nicks */ + break; + } + /* TODO test that the address ends with ',', ':', ' ', + * otherwise prefix nicks can match */ } if (ok) { @@ -1025,18 +1258,44 @@ static void* irc_thread (void *arg) static void* fifo_in_thread (void *arg) { char *line = NULL; int res, size=100; - line = (char*) malloc(size+1); + line = malloc(size+1); + assert(line); while ((res = getline((char**) &line, (size_t*) &size, stdin)) != -1) { - debug("i read and push %s\n", line); - push(&fifo_in, line, args.last_chan_in, args.last_nick_in, - args.last_chans_out); + debug("in_thread reads %s", line); + debug("i need to free %p", line); + if (line[0] == '[' && args.destination_prefix) + { + int i=0; + char *msg; + char *target = line+1; + if (!line[0]) + target = NULL; + + while (line[i] != ']' && line[i]) + i++; + if (!line[i]) + die(E_BADLINE, "Malformed address prefix"); + msg = line + i + 1; + if (msg[0] == ' ') + msg++; + if (i) + line[i] = 0; + cmd_msg(line, target, msg); + strncpy(args.last_chans_out, target, MAX_LEN-1); + } else { + /* No target specified, we attempt the default */ + cmd_msg(line, "", line); + } + // reallocate line, the popper will free the line - line = (char*) malloc(size+1); + line = malloc(size+1); + assert(line); } // sentinel - push(&fifo_in, NULL, NULL, NULL, NULL); - free(line); + debug("[thread_in] pushed sentinel"); + push_fifo_set(&fifos, NULL, "", NULL); + free(line); // which wasn't used return 0; } @@ -1046,17 +1305,16 @@ int start (int max_wait) { irc_session_t * s; pthread_t tid_irc, tid_in; - line l; - struct timeval tp1, tp2; - long tp; - int first = 1; + int i; int waiting = 0; + int cont = 1; + action *results; + int n_results; s = do_connect(); debug("Connection request successful!"); - debug("hd %d tl %d\n", fifo_in.hd, fifo_in.tl); debug("Starting threads..."); if (pthread_create (&tid_irc, 0, irc_thread, (void*) s) != 0) die(E_THREAD, "Could not create thread: %s", strerror(errno)); @@ -1068,7 +1326,7 @@ int start (int max_wait) if (args.show_inferred && args.default_destination == DEFAULT_LAST_OUT) fprintf(stderr, "[%s] ", args.last_chans_out); - gettimeofday(&tp1, NULL); + //gettimeofday(&tp1, NULL); if (!args.ready) { waiting = 0; @@ -1090,65 +1348,49 @@ int start (int max_wait) } } - // initialize last_chan_in and last_chan_out - strncpy(args.last_chan_in, first_chan(), MAX_LEN-1); - strncpy(args.last_chans_out, first_chan(), MAX_LEN-1); - - while ((l = pop(&fifo_in)).line) { - debug("startloop : got %s, waiting", l.line); - if (!args.ready) { + debug("[main] Starting loop"); + while (cont) { + n_results = pop_fifo_set(&fifos, &results); + debug("[main] I popped %d results", n_results); + for (i = 0; i < n_results; i++) { + if (!results[i].line) { + debug("[main] Sentinel seen, we will exit"); + cont = 0; // sentinel + } else { + debug("[main] manage line %s %s, pointer %p", + results[i].destination, results[i].line, results[i].full_line ); + do_cmd_msg(s, results[i].destination, results[i].line); + } + } + // now, we free stuff + for (i = 0; i < n_results; i++) + if (results[i].full_line) + free(results[i].full_line); + debug("[main] I managed my lines"); + if (cont && !args.ready) { info("Connection lost, reconnecting..."); return start(max_wait); } - debug("ready", l.line); - /* TODO no wait on empty lines */ /* TODO separate delay per channel */ - gettimeofday(&tp2, NULL); - tp = 1000000*(tp2.tv_sec - tp1.tv_sec) + tp2.tv_usec - tp1.tv_usec; - if (tp < args.interval && !first) - usleep(args.interval - tp); - first = 0; - - if (l.line[0] == '[' && args.destination_prefix) - { - int i=0; - char *msg; - char *tmp; - char *target = l.line+1; - if (!l.line[0]) - target = NULL; - - while (l.line[i] != ']' && l.line[i]) - i++; - if (!l.line[i]) - die(E_BADLINE, "Malformed address prefix"); - msg = l.line + i + 1; - if (msg[0] == ' ') - msg++; - l.line[i] = 0; - tmp = l.line; - l.line = msg; - cmd_msg(s, target, l); - l.line = tmp; - strncpy(l.last_chans_out, target, MAX_LEN-1); - } else { - /* No target specified, we attempt the default */ - cmd_msg(s, "", l); - } + // gettimeofday(&tp2, NULL); + // tp = 1000000*(tp2.tv_sec - tp1.tv_sec) + tp2.tv_usec - tp1.tv_usec; + // if (tp < args.interval && !first) + // usleep(args.interval - tp); + // first = 0; if (args.show_inferred && args.default_destination == DEFAULT_LAST_OUT) - fprintf(stderr, "[%s] ", l.last_chans_out); - usleep(args.interval); + fprintf(stderr, "[%s] ", args.last_chans_out); + + if (cont) + usleep(args.interval); - debug("endloop"); - free(l.line); + debug("[main] endloop"); } - debug("exiting"); + debug("[main] exiting"); - usleep(2*args.interval); irc_disconnect(s); return 0; @@ -1163,7 +1405,7 @@ int main (int argc, char **argv) argp_parse (&argp, argc, argv, 0, 0, &args); // initialize the fifo - init(&fifo_in); + init_fifo_set(&fifos); // start trying to connet with the initial retry interval return start(args.retry_after);