#include #include #include #include #include #include #include struct chat_session { stralloc name; session* s; stralloc line; struct chat_session* next; struct chat_session* prev; }; struct chat_service { struct chat_session* head; struct chat_session* tail; strhash users; }; void open_handler(session* s) { struct chat_session* sp = calloc(1, sizeof(struct chat_session)); if (!sp) { close_session(s); return; } /* link it back and forth */ s->handle = sp; sp->s = s; /* greeting */ mpx_session_printf(s, "Your nick name, please.\r\n"); } void read_handler(session* s) { struct chat_service* gs = s->global_handle; struct chat_session* sp = s->handle; if (mpx_session_scan(s, &sp->line) != 1) { close_session(s); return; } if (sp->line.len == 0) { /* ignore empty input lines */ mpx_session_printf(s, "Empty are your words...\r\n"); } else if (sp->name.len == 0) { /* interpret input as name */ stralloc_0(&sp->line); if (strhash_add(&gs->users, sp->line.s, 0)) { --sp->line.len; /* remove 0-byte */ stralloc_copy(&sp->name, &sp->line); /* append sp to the linear list of chat sessions */ sp->prev = gs->tail; if (gs->tail) { gs->tail->next = sp; } else { gs->head = sp; } gs->tail = sp; mpx_session_printf(s, "%.*s, you are welcome!\r\n", sp->name.len, sp->name.s); } else { mpx_session_printf(s, "Your nick name %s has already been taken; please try again!\r\n", sp->line.s); } } else { /* chatting */ for (struct chat_session* other = gs->head; other; other = other->next) { if (other != sp) { mpx_session_printf(other->s, "%.*s: %.*s\r\n", sp->name.len, sp->name.s, sp->line.len, sp->line.s); } } } } void hangup_handler(session* s) { struct chat_service* gs = s->global_handle; struct chat_session* sp = s->handle; if (sp->name.len > 0) { if (sp->prev) { sp->prev->next = sp->next; } else { gs->head = sp->next; } if (sp->next) { sp->next->prev = sp->prev; } else { gs->tail = sp->prev; } stralloc_free(&sp->name); } stralloc_free(&sp->line); free(sp); } int main(int argc, char** argv) { char* cmdname = *argv++; --argc; outbuf err = {2}; if (argc != 1) { outbuf_printf(&err, "Usage: %s hostport\n", cmdname); outbuf_flush(&err); exit(1); } char* hostport_string = *argv++; --argc; hostport hp; if (!parse_hostport(hostport_string, &hp, 33033)) { outbuf_printf(&err, "%s: hostport in conformance to RFC 2396 expected\n", cmdname); exit(1); } struct chat_service chat = {0}; strhash_alloc(&chat.users, 16); run_mpx_service(&hp, "(.*?)\r?\n", open_handler, read_handler, hangup_handler, &chat); }