/* handle a password response from a server */ static void serverpassword(imc_connect *c, const char *argument) { char arg1[3], name[IMC_MNAME_LENGTH], pw[IMC_PW_LENGTH], version[20]; imc_info *i; argument=imc_getarg(argument, arg1, 4); /* has to be PW */ argument=imc_getarg(argument, name, IMC_MNAME_LENGTH); argument=imc_getarg(argument, pw, IMC_PW_LENGTH); argument=imc_getarg(argument, version, 20); if (strcasecmp(arg1, "PW")) { imc_logstring("%s: non-PW password packet", imc_getconnectname(c)); do_close(c); return; } i=imc_getinfo(name); if (!i || strcmp(i->serverpw, pw) || i != c->info) { if ((!i || !(i->flags & IMC_QUIET)) && !(c->info->flags & IMC_QUIET)) imc_logstring("%s: password failure for %s", imc_getconnectname(c), name); do_close(c); return; } if (i->connection) /* kill old connections */ do_close(i->connection); i->connection = c; c->state = IMC_CONNECTED; c->spamcounter1 = 0; c->spamcounter2 = 0; /* check for a version string (assume version 0 if not present) */ if (sscanf(version, "version=%hu", &c->version)!=1) c->version=0; /* check for generator/interpreter */ if (!imc_vinfo[c->version].generate || !imc_vinfo[c->version].interpret) { if (!(i->flags & IMC_QUIET)) imc_logstring("%s: unsupported version %d", imc_getconnectname(c), c->version); do_close(c); return; } if (!(i->flags & IMC_QUIET)) imc_logstring("%s: connected (version %d)", imc_getconnectname(c), c->version); c->info->timer_duration=IMC_MIN_RECONNECT_TIME; c->info->last_connected=imc_now; imc_cancel_event(ev_login_timeout, c); imc_cancel_event(ev_reconnect, c->info); }
void imc_delete_info(imc_info *i) { imc_connect *c; imc_info *last; for (c=imc_connect_list; c; c=c->next) if (c->info==i) do_close(c); if (i==imc_info_list) imc_info_list=i->next; else { for (last=imc_info_list; last && last->next!=i; last=last->next) ; if (!last) imc_logerror("imc_delete_info: not in list"); else last->next=i->next; } if (i->name) imc_strfree(i->name); if (i->host) imc_strfree(i->host); if (i->clientpw) imc_strfree(i->clientpw); if (i->serverpw) imc_strfree(i->serverpw); imc_cancel_event(NULL, i); imc_free(i, sizeof(*i)); }
/* free buffers and extract 'c' from imc_connect_list * called from imc_idle_select when we're done with a connection with * c->state==IMC_CLOSED */ void imc_extract_connect(imc_connect *c) { imc_connect *c_find; if (c->state!=IMC_CLOSED) { imc_logerror("imc_extract_connect: non-closed connection"); return; } imc_free(c->inbuf, c->insize); imc_free(c->outbuf, c->outsize); if (c==imc_connect_list) imc_connect_list=c->next; else { for (c_find=imc_connect_list; c_find && c_find->next!=c; c_find=c_find->next) ; if (!c_find) imc_logerror("imc_extract_connect: not in imc_connect_list"); else c_find->next=c->next; } imc_cancel_event(NULL, c); imc_free(c, sizeof(*c)); }
/* free_mail: free a mail structure */ static void free_mail(imc_mail *p) { if (!p) { imc_logerror("BUG: free_mail: freeing NULL pointer"); return; } if (p->usage) { imc_logerror("BUG: free_mail: freeing mail at %p with usage=%d", p, p->usage); return; } if (p->from) imc_strfree(p->from); if (p->to) imc_strfree(p->to); if (p->id) imc_strfree(p->id); if (p->text) imc_strfree(p->text); if (p->subject) imc_strfree(p->subject); if (p->date) imc_strfree(p->date); imc_cancel_event(NULL, p); imc_free(p, sizeof(*p)); }
/* imc_mail_shutdown: shut down the mailer */ void imc_mail_shutdown(void) { save_mq(); save_ml(); save_idlist(); free_mq(); free_ml(); free_idlist(); imc_cancel_event(ev_mailid_expire, NULL); }
void icec_recv_update(const char *from, const char *chan, const char *owner, const char *operators, const char *policy, const char *invited, const char *excluded) { ice_channel *c; const char *mud; mud = imc_mudof(from); /* forged? */ if(!strchr(chan, ':') || strcasecmp(mud, ice_mudof(chan))) { return; } c = icec_findchannel(chan); if(!c) { c = imc_malloc(sizeof(*c)); c->name = imc_strdup(chan); c->owner = imc_strdup(owner); c->operators = imc_strdup(operators); c->invited = imc_strdup(invited); c->excluded = imc_strdup(excluded); c->local = NULL; c->active = NULL; c->next = icec_channel_list; icec_channel_list = c; } else { imc_strfree(c->owner); imc_strfree(c->operators); imc_strfree(c->invited); imc_strfree(c->excluded); c->name = imc_strdup(chan); c->owner = imc_strdup(owner); c->operators = imc_strdup(operators); c->invited = imc_strdup(invited); c->excluded = imc_strdup(excluded); } if(!strcasecmp(policy, "open")) { c->policy = ICE_OPEN; } else if(!strcasecmp(policy, "closed")) { c->policy = ICE_CLOSED; } else { c->policy = ICE_PRIVATE; } if(c->local && !ice_audible(c, imc_name)) { icec_localfree(c); } icec_notify_update(c); imc_cancel_event(ev_icec_timeout, c); imc_add_event(ICEC_TIMEOUT, ev_icec_timeout, c, 0); }
/* free_mailid: free a mailid */ static void free_mailid(imc_mailid *p) { if (!p) { imc_logerror("BUG: free_mailid: freeing NULL pointer"); return; } if (p->id) imc_strfree(p->id); imc_cancel_event(NULL, p); imc_free(p, sizeof(*p)); }
/* free_qnode: free a qnode */ static void free_qnode(imc_qnode *q) { if (!q) { imc_logerror("BUG: free_qnode: freeing NULL pointer"); return; } if (q->tomud) imc_strfree(q->tomud); if (q->data && !--q->data->usage) delete_ml(q->data); imc_cancel_event(NULL, q); imc_free(q, sizeof(*q)); }
/* handle a password from a client */ static void clientpassword(imc_connect *c, const char *argument) { char arg1[3], name[IMC_MNAME_LENGTH], pw[IMC_PW_LENGTH], version[20]; imc_info *i; char response[IMC_PACKET_LENGTH]; argument=imc_getarg(argument, arg1, 4); /* packet type (has to be PW) */ argument=imc_getarg(argument, name, IMC_MNAME_LENGTH); /* remote mud name */ argument=imc_getarg(argument, pw, IMC_PW_LENGTH); /* password */ argument=imc_getarg(argument, version, 20); /* optional version=n string */ if (strcasecmp(arg1, "PW")) { imc_logstring("%s: non-PW password packet", imc_getconnectname(c)); do_close(c); return; } /* do we know them, and do they have the right password? */ i=imc_getinfo(name); if (!i || strcmp(i->clientpw, pw)) { if (!i || !(i->flags & IMC_QUIET)) imc_logstring("%s: password failure for %s", imc_getconnectname(c), name); do_close(c); return; } /* deny access if deny flag is set (good for eg. muds that start crashing * on rwho) */ if (i->flags & IMC_DENY) { if (!(i->flags & IMC_QUIET)) imc_logstring("%s: denying connection", name); do_close(c); return; } if (i->connection) /* kill old connections */ do_close(i->connection); /* register them */ i->connection = c; c->state = IMC_CONNECTED; c->info = i; c->spamcounter1 = 0; c->spamcounter2 = 0; /* check for a version string (assume version 0 if not present) */ if (sscanf(version, "version=%hu", &c->version)!=1) c->version=0; /* check for generator/interpreter */ if (!imc_vinfo[c->version].generate || !imc_vinfo[c->version].interpret) { if (!(i->flags & IMC_QUIET)) imc_logstring("%s: unsupported version %d", imc_getconnectname(c), c->version); do_close(c); return; } /* send our response */ sprintf(response, "PW %s %s version=%d", imc_name, i->serverpw, IMC_VERSION); do_send(c, response); if (!(i->flags & IMC_QUIET)) imc_logstring("%s: connected (version %d)", imc_getconnectname(c), c->version); c->info->timer_duration=IMC_MIN_RECONNECT_TIME; c->info->last_connected=imc_now; imc_cancel_event(ev_login_timeout, c); imc_cancel_event(ev_reconnect, c->info); }
/* put a line onto descriptors output buffer */ static void do_send(imc_connect *c, const char *line) { int len; char *newbuf; int newsize=c->outsize; if (c->state==IMC_CLOSED) return; // imc_debug(c, 1, line); /* log outgoing traffic */ if (!c->outbuf[0]) c->newoutput=1; len=strlen(c->outbuf)+strlen(line)+3; if (len > c->outsize) { #ifdef SHOW_OVERFLOW /* not an error anymore, expected and handled - shogar */ if (len > IMC_MAXBUF) { if (!c->info || !(c->info->flags & IMC_QUIET)) imc_logerror("%s: output buffer overflow", imc_getconnectname(c)); imc_logerror("%d: was allocated", c->outsize); // imc_logerror("current buf: %s", c->outbuf); // do_close(c); // imc_free(c->outbuf,c->outsize); // c->outsize=IMC_MINBUF; // c->outbuf= imc_malloc(c->outsize); // len=strlen(line)+3; // return; } #endif while(newsize < len) newsize*=2; newbuf=imc_malloc(newsize); strcpy(newbuf, c->outbuf); imc_free(c->outbuf, c->outsize); c->outbuf=newbuf; c->outsize=newsize; } if (len<c->outsize/2 && len >= IMC_MINBUF) { newsize=c->outsize/2; newbuf=imc_malloc(newsize); strcpy(newbuf, c->outbuf); imc_free(c->outbuf, c->outsize); c->outbuf=newbuf; c->outsize=newsize; } strcat(c->outbuf, line); strcat(c->outbuf, "\n\r"); if (strlen(c->outbuf)>=c->outsize/2) { imc_cancel_event(ev_shrink_output, c); imc_add_event(IMC_SHRINKTIME, ev_shrink_output, c, 0); } }
/* read waiting data from descriptor. * read to a temp buffer to avoid repeated allocations */ static void do_read(imc_connect *c) { int size; int r; char temp[IMC_MAXBUF]; char *newbuf; int newsize; r=read(c->desc, temp, IMC_MAXBUF-1); if (!r || (r<0 && errno != EAGAIN && errno != EWOULDBLOCK)) { if (!c->info || !(c->info->flags & IMC_QUIET)) { if (r<0) /* read error */ { imc_lerror("%s: read", imc_getconnectname(c)); } else /* socket was closed */ { imc_logerror("%s: read: EOF", imc_getconnectname(c)); } } do_close(c); return; } if (r<0) /* EAGAIN error */ return; temp[r]=0; size=strlen(c->inbuf)+r+1; if (size>=c->insize) { #ifdef SHOW_OVERFLOW /* not an error anymore, expected and handled - shogar */ if (size>IMC_MAXBUF) { imc_logerror("%s: input buffer overflow", imc_getconnectname(c)); imc_logerror("%d: was allocated", c->insize); // do_close(c); // imc_free(c->inbuf,c->insize); // c->insize=IMC_MINBUF; // c->inbuf= imc_malloc(c->insize); // size = r + 1; // return; } #endif newsize=c->insize; while(newsize<size) newsize*=2; newbuf=imc_malloc(newsize); strcpy(newbuf, c->inbuf); imc_free(c->inbuf, c->insize); c->inbuf=newbuf; c->insize=newsize; } if (size>c->insize/2) { imc_cancel_event(ev_shrink_input, c); imc_add_event(IMC_SHRINKTIME, ev_shrink_input, c, 0); } if (size<c->insize/2 && size >= IMC_MINBUF) { newsize=c->insize; newsize/=2; newbuf=imc_malloc(newsize); strcpy(newbuf, c->inbuf); imc_free(c->inbuf, c->insize); c->inbuf=newbuf; c->insize=newsize; } strcat(c->inbuf, temp); imc_stats.rx_bytes += r; }
/* close given connection */ static void do_close(imc_connect *c) { const char *name; imc_reminfo *r; if (c->info) /* if our switched hub, get a new one right away - shogar */ { if (!imc_is_router && (c->info->flags & IMC_NEW_HUB) && c->info == imc_info_list) { imc_cancel_event(ev_imc_pollforhub,NULL); imc_cancel_event(ev_imc_optimize,NULL); imc_add_event(10, ev_imc_pollforhub, NULL, 1); imc_add_event(70, ev_imc_optimize, NULL, 1); } } if (c->state==IMC_CLOSED) return; name=imc_getconnectname(c); if(name && c->state == IMC_CONNECTED) /* dont send if never connected */ { imc_close_notify(name); close(c->desc); /* dont close if closed */ } if (c->state == IMC_CONNECTED) c->info->connection=NULL; /* handle reconnects */ if (c->info) if ((c->info->flags & IMC_RECONNECT) && !(c->info->flags & IMC_DENY) && !(c->info->flags & IMC_CLIENT)) { imc_setup_reconnect(c->info); } c->state=IMC_CLOSED; /* only log after we've set the state, in case imc_logstring * sends packets itself (problems with eg. output buffer overflow). */ if (!c->info || !(c->info->flags & IMC_QUIET)) { name=imc_getconnectname(c); if(name) imc_logstring("%s: closing link", name); } if (c->info) { r=imc_find_reminfo(c->info->name, 1); if (r) imc_delete_reminfo(r); } if(c->desc) close(c->desc); c->desc=0; c->inbuf[0]=0; c->outbuf[0]=0; }