00001
00070
00071 #define BORIS_VERSION_MAJ 0
00072 #define BORIS_VERSION_MIN 5
00073 #define BORIS_VERSION_PAT 0
00074
00142
00143
00144
00145
00146
00147 #if (defined(_MSC_VER) || defined(__WIN32__)) && !defined(WIN32)
00148 #define WIN32
00149 #endif
00150
00151 #if defined(WIN32)
00152
00153 #define USE_WIN32_SOCKETS
00154
00159 #ifndef __GNUC__
00160 #pragma comment(lib, "ws2_32.lib")
00161 #endif
00162
00163 #ifndef _WIN32_WINNT
00164
00165 #define _WIN32_WINNT 0x0501
00166 #endif
00167
00169 #define MKDIR(d) mkdir(d)
00170 #else
00171
00172 #define USE_BSD_SOCKETS
00173
00175 #define MKDIR(d) mkdir(d, 0777)
00176 #endif
00177
00179 #define SOCKETIO_LISTEN_QUEUE 10
00180
00182 #define TELNETCLIENT_OUTPUT_BUFFER_SZ 4096
00183
00185 #define TELNETCLIENT_INPUT_BUFFER_SZ 256
00186
00187
00188
00189
00190
00191 #include <assert.h>
00192 #include <ctype.h>
00193 #include <dirent.h>
00194 #include <errno.h>
00195 #include <inttypes.h>
00196 #include <limits.h>
00197 #include <math.h>
00198 #include <signal.h>
00199 #include <stdarg.h>
00200 #include <stddef.h>
00201 #include <stdint.h>
00202 #include <stdio.h>
00203 #include <stdlib.h>
00204 #include <string.h>
00205 #ifdef _XOPEN_SOURCE
00206 #include <strings.h>
00207 #endif
00208 #include <sys/stat.h>
00209 #include <sys/types.h>
00210 #include <time.h>
00211
00212 #if defined(USE_BSD_SOCKETS)
00213 #include <arpa/inet.h>
00214 #include <errno.h>
00215 #include <fcntl.h>
00216 #include <netdb.h>
00217 #include <netinet/in.h>
00218 #include <sys/select.h>
00219 #include <sys/socket.h>
00220 #include <sys/types.h>
00221 #include <unistd.h>
00222 #elif defined(USE_WIN32_SOCKETS)
00223 #include <windows.h>
00224 #include <winsock2.h>
00225 #include <ws2tcpip.h>
00226 #else
00227 #error Must define either USE_BSD_SOCKETS or USE_WIN32_SOCKETS
00228 #endif
00229
00230 #include "boris.h"
00231 #include "list.h"
00232 #include "plugin.h"
00233
00234
00235
00236
00237 #if !defined(__STDC_VERSION__) || !(__STDC_VERSION__ >= 199901L)
00238 #warning Requires C99
00239 #endif
00240
00241
00242
00244 #define FOURCC(a,b,c,d) ( \
00245 ((uint_least32_t)(d)<<24) \
00246 |((uint_least32_t)(c)<<16) \
00247 |((uint_least32_t)(b)<<8) \
00248 |(a))
00249
00251 #define _make_name2(x,y) x##y
00252
00254 #define _make_name(x,y) _make_name2(x,y)
00255
00257 #define _make_string2(x) #x
00258
00260 #define _make_string(x) _make_string2(x)
00261
00263 #define VAR(x) _make_name(x,__LINE__)
00264
00265 #if defined(BORIS_VERSION_PAT) && (BORIS_VERSION_PAT > 0)
00266
00267 # define BORIS_VERSION_STR \
00268 _make_string(BORIS_VERSION_MAJ) "." \
00269 _make_string(BORIS_VERSION_MIN) "p" \
00270 _make_string(BORIS_VERSION_PAT)
00271 #else
00272 # define BORIS_VERSION_STR \
00273 _make_string(BORIS_VERSION_MAJ) "." \
00274 _make_string(BORIS_VERSION_MIN)
00275 #endif
00276
00277
00278 #ifndef NDEBUG
00279
00280 #define EXPORT
00281 #else
00282
00283 #define EXPORT static
00284 #endif
00285
00286
00287
00289 #define WR_BE32(dest, offset, value) do { \
00290 unsigned VAR(tmp)=value; \
00291 (dest)[offset]=(VAR(tmp)/16777216L)%256; \
00292 (dest)[(offset)+1]=(VAR(tmp)/65536L)%256; \
00293 (dest)[(offset)+2]=(VAR(tmp)/256)%256; \
00294 (dest)[(offset)+3]=VAR(tmp)%256; \
00295 } while(0)
00296
00298 #define WR_BE16(dest, offset, value) do { \
00299 unsigned VAR(tmp)=value; \
00300 (dest)[offset]=(VAR(tmp)/256)%256; \
00301 (dest)[(offset)+1]=VAR(tmp)%256; \
00302 } while(0)
00303
00305 #define WR_BE64(dest, offset, value) do { \
00306 unsigned long long VAR(tmp)=value; \
00307 (dest)[offset]=((VAR(tmp))>>56)&255; \
00308 (dest)[(offset)+1]=((VAR(tmp))>>48)&255; \
00309 (dest)[(offset)+2]=((VAR(tmp))>>40)&255; \
00310 (dest)[(offset)+3]=((VAR(tmp))>>32)&255; \
00311 (dest)[(offset)+4]=((VAR(tmp))>>24)&255; \
00312 (dest)[(offset)+5]=((VAR(tmp))>>16)&255; \
00313 (dest)[(offset)+6]=((VAR(tmp))>>8)&255; \
00314 (dest)[(offset)+7]=(VAR(tmp))&255; \
00315 } while(0)
00316
00318 #define RD_BE16(src, offset) ((((src)[offset]&255u)<<8)|((src)[(offset)+1]&255u))
00319
00321 #define RD_BE32(src, offset) (\
00322 (((src)[offset]&255ul)<<24) \
00323 |(((src)[(offset)+1]&255ul)<<16) \
00324 |(((src)[(offset)+2]&255ul)<<8) \
00325 |((src)[(offset)+3]&255ul))
00326
00328 #define RD_BE64(src, offset) (\
00329 (((src)[offset]&255ull)<<56) \
00330 |(((src)[(offset)+1]&255ull)<<48) \
00331 |(((src)[(offset)+2]&255ull)<<40) \
00332 |(((src)[(offset)+3]&255ull)<<32) \
00333 |(((src)[(offset)+4]&255ull)<<24) \
00334 |(((src)[(offset)+5]&255ull)<<16) \
00335 |(((src)[(offset)+6]&255ull)<<8) \
00336 |((src)[(offset)+7]&255ull))
00337
00338
00339
00341 #define BITFIELD(bits, type) (((bits)+(CHAR_BIT*sizeof(type))-1)/(CHAR_BIT*sizeof(type)))
00342
00344 #define BITSET(x, bit) (x)[(bit)/((CHAR_BIT*sizeof *(x)))]|=1<<((bit)&((CHAR_BIT*sizeof *(x))-1))
00345
00347 #define BITCLR(x, bit) (x)[(bit)/((CHAR_BIT*sizeof *(x)))]&=~(1<<((bit)&((CHAR_BIT*sizeof *(x))-1)))
00348
00350 #define BITINV(x, bit) (x)[(bit)/((CHAR_BIT*sizeof *(x)))]^=1<<((bit)&((CHAR_BIT*sizeof *(x))-1))
00351
00353 #define BITTEST(x, bit) ((x)[(bit)/((CHAR_BIT*sizeof *(x)))]&(1<<((bit)&((CHAR_BIT*sizeof *(x))-1))))
00354
00356 #define BITRANGE(x, bit) ((bit)<(sizeof(x)*CHAR_BIT))
00357
00358
00359
00360
00361
00362
00364 #define VERBOSE(...) fprintf(stderr, __VA_ARGS__)
00365
00366 #ifdef NDEBUG
00367 # define DEBUG(...)
00368 # define DEBUG_MSG(msg)
00369 # define HEXDUMP(data, len, ...)
00370 #else
00371
00373 # define DEBUG(msg, ...) fprintf(stderr, "DEBUG:%s():%d:" msg, __func__, __LINE__, ## __VA_ARGS__);
00374
00376 # define DEBUG_MSG(msg) fprintf(stderr, "ERROR:%s():%d:" msg "\n", __func__, __LINE__);
00377
00379 # define HEXDUMP(data, len, ...) do { fprintf(stderr, __VA_ARGS__); util_hexdump(stderr, data, len); } while(0)
00380 #endif
00381
00382 #ifdef NTRACE
00383 # define TRACE(...)
00384 # define HEXDUMP_TRACE(data, len, ...)
00385 #else
00386
00387 # define TRACE(f, ...) fprintf(stderr, "TRACE:%s():%u:" f, __func__, __LINE__, __VA_ARGS__)
00388
00389 # define HEXDUMP_TRACE(data, len, ...) HEXDUMP(data, len, __VA_ARGS__)
00390 #endif
00391
00392
00394 #define TRACE_MSG(m) TRACE("%s\n", m);
00395
00397 #define ERROR_FMT(msg, ...) fprintf(stderr, "ERROR:%s():%d:" msg, __func__, __LINE__, __VA_ARGS__);
00398
00400 #define ERROR_MSG(msg) fprintf(stderr, "ERROR:%s():%d:" msg "\n", __func__, __LINE__);
00401
00403 #define TODO(msg) fprintf(stderr, "TODO:%s():%d:" msg "\n", __func__, __LINE__);
00404
00406 #define TRACE_ENTER() TRACE("%u:ENTER\n", __LINE__);
00407
00409 #define TRACE_EXIT() TRACE("%u:EXIT\n", __LINE__);
00410
00412 #define FAILON(e, reason, label) do { if(e) { fprintf(stderr, "FAILED:%s:%s\n", reason, strerror(errno)); goto label; } } while(0)
00413
00415 #define PERROR(msg) fprintf(stderr, "ERROR:%s():%d:%s:%s\n", __func__, __LINE__, msg, strerror(errno));
00416
00418 #define DIE() do { ERROR_MSG("abort!"); abort(); } while(0)
00419
00420 #ifndef NDEBUG
00421 #include <string.h>
00423 # define JUNKINIT(ptr, len) memset((ptr), 0xBB, (len));
00424 #else
00425 # define JUNKINIT(ptr, len)
00426 #endif
00427
00428
00429
00431 #define REFCOUNT_TYPE int
00432
00434 #define REFCOUNT_NAME _referencecount
00435
00437 #define REFCOUNT_INIT(obj) ((obj)->REFCOUNT_NAME=0)
00438
00440 #define REFCOUNT_TAKE(obj) ((obj)->REFCOUNT_NAME++)
00441
00443 #define REFCOUNT_PUT(obj, free_action) do { \
00444 assert((obj)->REFCOUNT_NAME>0); \
00445 if(--(obj)->REFCOUNT_NAME<=0) { \
00446 free_action; \
00447 } \
00448 } while(0)
00449
00451 #define REFCOUNT_GET(obj) do { (obj)->REFCOUNT_NAME++; } while(0)
00452
00453
00454 #ifdef __GNUC__
00455
00456 #define GCC_ONLY(x) x
00457 #else
00458
00459 #define GCC_ONLY(x)
00460 #endif
00461
00463 #define UNUSED GCC_ONLY(__attribute__((unused)))
00464
00465
00466
00467
00468
00469 struct telnetclient;
00470
00471 struct socketio_handle;
00472
00473 struct menuitem;
00474
00476 struct menuinfo {
00477 LIST_HEAD(struct, struct menuitem) items;
00478 char *title;
00479 size_t title_width;
00480 struct menuitem *tail;
00481 };
00482
00484 struct formitem {
00485 LIST_ENTRY(struct formitem) item;
00486 unsigned value_index;
00487 char *name;
00488 unsigned flags;
00489 int (*form_check)(struct telnetclient *cl, const char *str);
00490 char *description;
00491 char *prompt;
00492 };
00493
00495 struct form_state {
00496 const struct form *form;
00497 const struct formitem *curritem;
00498 unsigned curr_i;
00499 unsigned nr_value;
00500 char **value;
00501 int done;
00502 };
00503
00505 struct form {
00506 LIST_HEAD(struct, struct formitem) items;
00507 struct formitem *tail;
00508 char *form_title;
00509 void (*form_close)(struct telnetclient *cl, struct form_state *fs);
00510 unsigned item_count;
00511 const char *message;
00512 };
00513
00514
00515
00516
00517
00519 static struct menuinfo gamemenu_login, gamemenu_main;
00520
00522 static struct mud_config {
00523 char *config_filename;
00524 char *menu_prompt;
00525 char *form_prompt;
00526 char *command_prompt;
00527 char *msg_errormain;
00528 char *msg_invalidselection;
00529 char *msg_invalidusername;
00530 char *msgfile_noaccount;
00531 char *msgfile_badpassword;
00532 char *msg_tryagain;
00533 char *msg_unsupported;
00534 char *msg_useralphanumeric;
00535 char *msg_usercreatesuccess;
00536 char *msg_userexists;
00537 char *msg_usermin3;
00538 char *msg_invalidcommand;
00539 char *msgfile_welcome;
00540 unsigned newuser_level;
00541 unsigned newuser_flags;
00542 unsigned newuser_allowed;
00543 char *eventlog_filename;
00544 char *eventlog_timeformat;
00545 char *msgfile_newuser_create;
00546 char *msgfile_newuser_deny;
00547 char *default_channels;
00548 unsigned webserver_port;
00549 char *form_newuser_filename;
00550 char *plugins;
00551 } mud_config;
00552
00553
00554
00555
00556 EXPORT void telnetclient_close(struct telnetclient *cl);
00557 EXPORT void menu_show(struct telnetclient *cl, const struct menuinfo *mi);
00558 EXPORT void menu_input(struct telnetclient *cl, const struct menuinfo *mi, const char *line);
00559 static void form_menu_lineinput(struct telnetclient *cl, const char *line);
00560
00561
00562
00563
00564
00568 static void b_log_dummy(int priority UNUSED, const char *domain UNUSED, const char *fmt, ...) {
00569 va_list ap;
00570 va_start(ap, fmt);
00571 fprintf(stderr, fmt, ap);
00572 va_end(ap);
00573 fputc('\n', stderr);
00574 }
00575
00576
00577 static int dummy_fdb_domain_init(const char *domain UNUSED) { return 0; }
00578 static struct fdb_write_handle *dummy_fdb_write_begin(const char *domain UNUSED, const char *id UNUSED) { return NULL; }
00579 static struct fdb_write_handle *dummy_fdb_write_begin_uint(const char *domain UNUSED, unsigned id UNUSED) { return NULL; }
00580 static int dummy_fdb_write_pair(struct fdb_write_handle *h UNUSED, const char *name UNUSED, const char *value_str UNUSED) { return 0; }
00581 static int dummy_fdb_write_format(struct fdb_write_handle *h UNUSED, const char *name UNUSED, const char *value_fmt UNUSED, ...) { return 0; }
00582 static int dummy_fdb_write_end(struct fdb_write_handle *h UNUSED) { return 0; }
00583 static void dummy_fdb_write_abort(struct fdb_write_handle *h UNUSED) { }
00584 static struct fdb_read_handle *dummy_fdb_read_begin(const char *domain UNUSED, const char *id UNUSED) { return NULL; }
00585 static struct fdb_read_handle *dummy_fdb_read_begin_uint(const char *domain UNUSED, unsigned id UNUSED) { return NULL; }
00586 static int dummy_fdb_read_next(struct fdb_read_handle *h UNUSED, const char **name UNUSED, const char **value UNUSED) { return 0; }
00587 static int dummy_fdb_read_end(struct fdb_read_handle *h UNUSED) { return 0; }
00588 static struct fdb_iterator *dummy_fdb_iterator_begin(const char *domain UNUSED) { return NULL; }
00589 static const char *dummy_fdb_iterator_next(struct fdb_iterator *it UNUSED) { return NULL; }
00590 static void dummy_fdb_iterator_end(struct fdb_iterator *it UNUSED) { }
00591
00592
00593
00594
00595
00596 void (*b_log)(int priority, const char *domain, const char *fmt, ...)=b_log_dummy;
00597 struct plugin_fdb_interface fdb = {
00598 dummy_fdb_domain_init,
00599 dummy_fdb_write_begin,
00600 dummy_fdb_write_begin_uint,
00601 dummy_fdb_write_pair,
00602 dummy_fdb_write_format,
00603 dummy_fdb_write_end,
00604 dummy_fdb_write_abort,
00605 dummy_fdb_read_begin,
00606 dummy_fdb_read_begin_uint,
00607 dummy_fdb_read_next,
00608 dummy_fdb_read_end,
00609 dummy_fdb_iterator_begin,
00610 dummy_fdb_iterator_next,
00611 dummy_fdb_iterator_end,
00612 };
00613 static const struct plugin_basic_class *fdb_owner;
00614
00615 struct plugin_room_interface room;
00616 static const struct plugin_basic_class *room_owner;
00617
00618 struct plugin_character_interface character;
00619 static const struct plugin_basic_class *character_owner;
00620
00621 struct plugin_channel_interface channel;
00622 static const struct plugin_basic_class *channel_owner;
00623
00627 int service_detach_log(void (*log)(int priority, const char *domain, const char *fmt, ...)) {
00628 if(log==b_log) {
00629 b_log=b_log_dummy;
00630 return 1;
00631 }
00632 return 0;
00633 }
00634
00638 void service_attach_log(void (*log)(int priority, const char *domain, const char *fmt, ...)) {
00639 b_log=log ? log : b_log_dummy;
00640 }
00641
00646 void service_detach_fdb(const struct plugin_basic_class *cls) {
00647 const struct plugin_fdb_interface dummy = {
00648 dummy_fdb_domain_init,
00649 dummy_fdb_write_begin,
00650 dummy_fdb_write_begin_uint,
00651 dummy_fdb_write_pair,
00652 dummy_fdb_write_format,
00653 dummy_fdb_write_end,
00654 dummy_fdb_write_abort,
00655 dummy_fdb_read_begin,
00656 dummy_fdb_read_begin_uint,
00657 dummy_fdb_read_next,
00658 dummy_fdb_read_end,
00659 dummy_fdb_iterator_begin,
00660 dummy_fdb_iterator_next,
00661 dummy_fdb_iterator_end,
00662 };
00663 if(!cls || fdb_owner==cls) {
00664 fdb_owner=NULL;
00665 fdb=dummy;
00666 }
00667 }
00668
00672 void service_attach_fdb(const struct plugin_basic_class *cls, const struct plugin_fdb_interface *interface) {
00673 fdb_owner=cls;
00674 if(interface) {
00675 fdb=*interface;
00676 }
00677 }
00678
00679 void service_detach_room(const struct plugin_basic_class *cls) {
00680 if(!cls || room_owner==cls) {
00681 room_owner=NULL;
00682 memset(&room, 0, sizeof room);
00683 }
00684 }
00685
00686 void service_attach_room(const struct plugin_basic_class *cls, const struct plugin_room_interface *interface) {
00687 room_owner=cls;
00688 if(interface) {
00689 room=*interface;
00690 }
00691 }
00692
00693 void service_detach_character(const struct plugin_basic_class *cls) {
00694 if(!cls || character_owner==cls) {
00695 character_owner=NULL;
00696 memset(&character, 0, sizeof character);
00697 }
00698 }
00699
00700 void service_attach_character(const struct plugin_basic_class *cls, const struct plugin_character_interface *interface) {
00701 character_owner=cls;
00702 if(interface) {
00703 character=*interface;
00704 }
00705 }
00706
00707 void service_detach_channel(const struct plugin_basic_class *cls) {
00708 if(!cls || channel_owner==cls) {
00709 channel_owner=NULL;
00710 memset(&channel, 0, sizeof channel);
00711 }
00712 }
00713
00714 void service_attach_channel(const struct plugin_basic_class *cls, const struct plugin_channel_interface *interface) {
00715 channel_owner=cls;
00716 if(interface) {
00717 channel=*interface;
00718 }
00719 }
00720
00721
00722
00723
00724
00726 #define UTIL_FNM_NOMATCH 1
00727
00729 #define UTIL_FNM_CASEFOLD 16
00730
00739 EXPORT int util_fnmatch(const char *pattern, const char *string, int flags) {
00740 char c;
00741
00742 while((c=*pattern++)) switch(c) {
00743 case '?':
00744 if(*string++==0) return UTIL_FNM_NOMATCH;
00745 break;
00746 case '*':
00747 if(!*pattern) return 0;
00748 for(;*string;string++) {
00749
00750 if(((flags&UTIL_FNM_CASEFOLD) ? tolower(*string)==tolower(*pattern) : *string==*pattern) && util_fnmatch(pattern, string, flags)==0) {
00751 return 0;
00752 }
00753 }
00754 return UTIL_FNM_NOMATCH;
00755 break;
00756 case '[': case ']': case '\\':
00757 TODO("support [] and \\");
00758 default:
00759 if((flags&UTIL_FNM_CASEFOLD) ? tolower(*string++)!=tolower(c) : *string++!=c) return UTIL_FNM_NOMATCH;
00760 }
00761 if(*string) return UTIL_FNM_NOMATCH;
00762 return 0;
00763 }
00764
00770 EXPORT char *util_textfile_load(const char *filename) {
00771 FILE *f;
00772 char *ret;
00773 long len;
00774 size_t res;
00775
00776 f=fopen(filename, "r");
00777 if(!f) {
00778 PERROR(filename);
00779 goto failure0;
00780 }
00781
00782 if(fseek(f, 0l, SEEK_END)!=0) {
00783 PERROR(filename);
00784 goto failure1;
00785 }
00786
00787 len=ftell(f);
00788 if(len==EOF) {
00789 PERROR(filename);
00790 goto failure1;
00791 }
00792
00793 assert(len>=0);
00794
00795 if(fseek(f, 0l, SEEK_SET)!=0) {
00796 PERROR(filename);
00797 goto failure1;
00798 }
00799
00800 ret=malloc((unsigned)len+1);
00801 if(!ret) {
00802 PERROR(filename);
00803 goto failure1;
00804 }
00805
00806 res=fread(ret, 1, (unsigned)len, f);
00807 if(ferror(f)) {
00808 PERROR(filename);
00809 goto failure2;
00810 }
00811
00812 ret[len]=0;
00813
00814 DEBUG("%s:loaded %ld bytes\n", filename, len);
00815
00816 fclose(f);
00817 return ret;
00818
00819 failure2:
00820 free(ret);
00821 failure1:
00822 fclose(f);
00823 failure0:
00824 return 0;
00825 }
00826
00831 EXPORT const char *util_getword(const char *s, char *out, size_t outlen) {
00832 const char *b, *e;
00833
00834
00835 for(b=s;isspace(*b);b++) ;
00836 for(e=b;*e && !isspace(*e);e++) ;
00837 snprintf(out, outlen, "%.*s", (int)(e-b), b);
00838 b=e;
00839 if(*b) b++;
00840 return b;
00841 }
00842
00843
00844
00845
00846
00848 struct util_strfile {
00849 const char *buf;
00850 };
00851
00853 EXPORT void util_strfile_open(struct util_strfile *h, const char *buf) {
00854 assert(h != NULL);
00855 assert(buf != NULL);
00856 h->buf=buf;
00857 }
00858
00860 EXPORT void util_strfile_close(struct util_strfile *h) {
00861 h->buf=NULL;
00862 }
00863
00865 EXPORT const char *util_strfile_readline(struct util_strfile *h, size_t *len) {
00866 const char *ret;
00867
00868 assert(h != NULL);
00869 assert(h->buf != NULL);
00870 ret=h->buf;
00871
00872 while(*h->buf && *h->buf!='\n') h->buf++;
00873 if(len)
00874 *len=h->buf-ret;
00875 if(*h->buf)
00876 h->buf++;
00877 return h->buf==ret?NULL:ret;
00878 }
00879
00884 EXPORT void trim_nl(char *line) {
00885 line=strrchr(line, '\n');
00886 if(line) *line=0;
00887 }
00888
00894 EXPORT char *trim_whitespace(char *line) {
00895 char *tmp;
00896 while(isspace(*line)) line++;
00897 for(tmp=line+strlen(line)-1;line<tmp && isspace(*tmp);tmp--) *tmp=0;
00898 return line;
00899 }
00900
00901
00902
00903
00904
00908 int parse_uint(const char *name, const char *value, unsigned *uint_p) {
00909 char *endptr;
00910 assert(uint_p != NULL);
00911
00912 if(!uint_p) return 0;
00913
00914 if(!value || !*value) {
00915 ERROR_FMT("%s:Empty string", name);
00916 return 0;
00917 }
00918 *uint_p=strtoul(value, &endptr, 0);
00919
00920 if(*endptr!=0) {
00921 ERROR_FMT("%s:Not a number", name);
00922 return 0;
00923 }
00924
00925 return 1;
00926 }
00927
00931 int parse_str(const char *name UNUSED, const char *value, char **str_p) {
00932 assert(str_p != NULL);
00933 assert(value != NULL);
00934 if(!str_p) return 0;
00935
00936 if(*str_p) free(*str_p);
00937 *str_p=strdup(value);
00938 if(!*str_p) {
00939 PERROR("strdup()");
00940 return 0;
00941 }
00942
00943 return 1;
00944 }
00945
00949 int parse_attr(const char *name, const char *value, struct attr_list *al) {
00950 struct attr_entry *at;
00951
00952 assert(name != NULL);
00953 assert(value != NULL);
00954 assert(al != NULL);
00955
00956 at=attr_find(al, name);
00957 if(!at) {
00958 return attr_add(al, name, value);
00959 }
00960 free(at->value);
00961 at->value=strdup(value);
00962 return 1;
00963 }
00964
00968 int value_set(const char *value, enum value_type type, void *p) {
00969 assert(p != NULL);
00970 assert(value != NULL);
00971
00972 if(!p || !value) return 0;
00973
00974 switch(type) {
00975 case VALUE_TYPE_STRING: {
00976 if(*(char**)p) free(*(char**)p);
00977 *(char**)p=strdup(value);
00978 if(!*(char**)p) {
00979 PERROR("strdup()");
00980 return 0;
00981 }
00982 return 1;
00983 }
00984 case VALUE_TYPE_UINT: {
00985 char *endptr;
00986 if(!*value) {
00987 ERROR_MSG("Empty string");
00988 return 0;
00989 }
00990 *(unsigned*)p=strtoul(value, &endptr, 0);
00991 if(*endptr!=0) {
00992 ERROR_FMT("Not a number:\"%s\"\n", value);
00993 return 0;
00994 }
00995 return 1;
00996 }
00997 }
00998
00999 return 0;
01000 }
01001
01007 const char *value_get(enum value_type type, void *p) {
01008 static char numbuf[22];
01009 switch(type) {
01010 case VALUE_TYPE_STRING:
01011 return *(char**)p;
01012 case VALUE_TYPE_UINT:
01013 snprintf(numbuf, sizeof numbuf, "%u", *(unsigned*)p);
01014 return numbuf;
01015 }
01016 return NULL;
01017 }
01018
01019
01020
01021
01022
01023 #ifdef WIN32
01024 #include <windows.h>
01028 typedef HMODULE dll_handle_t;
01029 typedef FARPROC dll_func_t;
01030 typedef void *dll_symbol_t;
01031 #define SOEXT ".dll"
01032 #else
01033 #include <dlfcn.h>
01037 typedef struct { void *h; } dll_handle_t;
01038 typedef int (*dll_func_t)();
01039 typedef void *dll_symbol_t;
01040 #ifdef __APPLE__
01041 #define SOEXT ".dylib"
01042 #else
01043 #define SOEXT ".so"
01044 #endif
01045 #endif
01046
01051 static void dll_show_error(const char *reason) {
01052 #ifdef WIN32
01053 LPTSTR lpMsgBuf;
01054 FormatMessage(
01055 FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM
01056 |FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
01057 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL);
01058 if(reason) {
01059 fprintf(stderr, "%s:%s\n", reason, lpMsgBuf);
01060 } else {
01061 fprintf(stderr, "%s\n", lpMsgBuf);
01062 }
01063 LocalFree(lpMsgBuf);
01064 #else
01065 const char *msg;
01066 msg=dlerror();
01067 if(msg) {
01068 if(reason) {
01069 fprintf(stderr, "%s:%s\n", reason, msg);
01070 } else {
01071 fprintf(stderr, "%s\n", msg);
01072 }
01073 }
01074 #endif
01075 }
01076
01086 EXPORT int dll_open(dll_handle_t *h, const char *filename) {
01087 char path[PATH_MAX];
01088 #ifdef WIN32
01089 unsigned i;
01090
01091 for(i=0;filename[i] && i<sizeof path-1;i++) {
01092 path[i]=filename[i]=='/'?'\\':filename[i];
01093 }
01094 path[i]=0;
01095 if(!strstr(filename, SOEXT)) {
01096 strcat(path, SOEXT);
01097 }
01098
01099 *h=LoadLibrary(filename);
01100 if(!*h) {
01101 #else
01102 strcpy(path, filename);
01103 if(!strstr(filename, SOEXT)) {
01104 strcat(path, SOEXT);
01105 }
01106 TRACE("dlopen(%s)\n", path);
01107 h->h=dlopen(path, RTLD_NOW|RTLD_LOCAL);
01108 if(!h->h) {
01109 #endif
01110 dll_show_error(path);
01111 return 0;
01112 }
01113 return 1;
01114 }
01115
01121 EXPORT void dll_close(dll_handle_t h) {
01122 #ifdef WIN32
01123 if(h.h) {
01124 if(!FreeLibrary(h)) {
01125 dll_show_error("FreeLibrary()");
01126 }
01127 }
01128 #else
01129 if(h.h) {
01130 if(dlclose(h.h)) {
01131 dll_show_error("dlclose()");
01132 }
01133 }
01134 #endif
01135 }
01136
01144 EXPORT dll_symbol_t dll_symbol(dll_handle_t h, const char *name) {
01145 dll_symbol_t ret;
01146 #ifdef WIN32
01147 ret=GetProcAddress(h, name);
01148 #else
01149 ret=dlsym(h.h, name);
01150 #endif
01151 if(!ret) {
01152 dll_show_error(name);
01153 }
01154 return ret;
01155 }
01156
01157
01158 #if 0
01159 EXPORT dll_func_t dll_func(dll_handle_t h, const char *name) {
01160 return (int(*)())dll_symbol(h, name);
01161 }
01162 #endif
01163
01164
01165
01166
01167
01168
01169
01170
01171 #if !defined(NTEST) || !defined(NDEBUG)
01172
01178 static const char *util_convertnumber(unsigned n, unsigned base, unsigned pad) {
01179 static char number_buffer[65];
01180 static const char tab[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-";
01181 char *o;
01182 size_t len;
01183 if(base<2) base=2;
01184 if(base>sizeof tab) base=sizeof tab;
01185 o=number_buffer+sizeof number_buffer;
01186 *--o=0;
01187 do {
01188 *--o=tab[n%base];
01189 n/=base;
01190 } while(n);
01191 len=number_buffer+sizeof number_buffer-1-o;
01192 if(pad && len<pad) {
01193 for(pad=pad-len;pad;pad--) {
01194 *--o=tab[0];
01195 }
01196 }
01197 return o;
01198 }
01199
01206 static void util_hexdump(FILE *f, const void *data, int len) {
01207 fprintf(f, "[%d]", len);
01208 while(len>0) {
01209 unsigned char ch=*(unsigned char*)data;
01210 if(isprint(ch)) {
01211 fprintf(f, " '%c'", ch);
01212 } else {
01213 fprintf(f, " 0x%02hhx", ch);
01214 }
01215 len--;
01216 data=((unsigned char*)data)+1;
01217 }
01218 fprintf(f, "\n");
01219 }
01220 #endif
01221
01222
01223
01224
01225
01227 #define SHVAR_ID_MAX 128
01228
01230 #define SHVAR_ESCAPE '$'
01231
01233 EXPORT int shvar_eval(char *out, size_t len, const char *src, const char *(*match)(const char *key)) {
01234 const char *old;
01235 char key[SHVAR_ID_MAX];
01236 while(*src && len>0) {
01237 if(*src==SHVAR_ESCAPE) {
01238 const char *key_start, *key_end;
01239 old=src;
01240 src++;
01241 if(*src=='{' || *src=='(') {
01242 char end_char;
01243 end_char=*src=='{'?'}':')';
01244 src++;
01245 key_start=key_end=src;
01246 while(*src!=end_char) {
01247 if(!*src) {
01248 size_t tmplen;
01249 tmplen=strlen(old);
01250 if(tmplen>=len) tmplen=len-1;
01251 memcpy(out, old, tmplen);
01252 out[tmplen]=0;
01253 return 0;
01254 }
01255 src++;
01256 }
01257 key_end=src;
01258 src++;
01259 } else if(*src==SHVAR_ESCAPE) {
01260 *out++=*src++;
01261 len--;
01262 continue;
01263 } else {
01264 key_start=src;
01265 while(*src && len>0) {
01266 if(!isalnum(*src) && *src!='_') {
01267 break;
01268 }
01269 src++;
01270 }
01271 key_end=src;
01272 }
01273 if(match && key_end>=key_start) {
01274 const char *tmp;
01275 size_t tmplen;
01276 assert(key_start<=key_end);
01277 memcpy(key, key_start, (size_t)(key_end-key_start));
01278 key[key_end-key_start]=0;
01279 tmp=match(key);
01280 if(tmp) {
01281 tmplen=strlen(tmp);
01282 if(tmplen>len) return 0;
01283 memcpy(out, tmp, tmplen);
01284 out+=tmplen;
01285 len-=tmplen;
01286 }
01287 }
01288 } else {
01289 *out++=*src++;
01290 len--;
01291 }
01292 }
01293 if(len>0) {
01294 *out++=0;
01295 len--;
01296 return *src==0;
01297 }
01298 *out=0;
01299 return 0;
01300 }
01301
01302
01303
01304
01305
01307 #define HEAPQUEUE_LEFT(i) (2*(i)+1)
01308
01310 #define HEAPQUEUE_RIGHT(i) (2*(i)+2)
01311
01313 #define HEAPQUEUE_PARENT(i) (((i)-1)/2)
01314
01316 struct heapqueue_elm {
01317 unsigned d;
01319 };
01320
01322 static struct heapqueue_elm heap[512];
01323
01325 static unsigned heap_len;
01326
01331 static inline int heapqueue_greaterthan(struct heapqueue_elm *a, struct heapqueue_elm *b) {
01332 assert(a!=NULL);
01333 assert(b!=NULL);
01334 return a->d>b->d;
01335 }
01336
01342 static int heapqueue_ll_siftdown(unsigned i, struct heapqueue_elm *elm) {
01343 assert(elm!=NULL);
01344 assert(i<heap_len || i==0);
01345 while(HEAPQUEUE_LEFT(i)<heap_len) {
01346 unsigned child=HEAPQUEUE_LEFT(i);
01347
01348
01349 if(child+1<heap_len && heapqueue_greaterthan(&heap[child], &heap[child+1])) {
01350 child++;
01351 }
01352
01353
01354 if(!(heapqueue_greaterthan(elm, &heap[child]))) {
01355 break;
01356 }
01357
01358 TRACE("swap hole %d with entry %d\n", i, child);
01359 heap[i]=heap[child];
01360 i=child;
01361 }
01362 TRACE("chosen position %d for hole.\n", i);
01363 return i;
01364 }
01365
01371 static int heapqueue_ll_siftup(unsigned i, struct heapqueue_elm *elm) {
01372 assert(elm!=NULL);
01373 assert(i<heap_len);
01374 while(i>0 && heapqueue_greaterthan(&heap[HEAPQUEUE_PARENT(i)], elm)) {
01375
01376 heap[i]=heap[HEAPQUEUE_PARENT(i)];
01377 i=HEAPQUEUE_PARENT(i);
01378 }
01379 return i;
01380 }
01381
01384 EXPORT int heapqueue_cancel(unsigned i, struct heapqueue_elm *ret) {
01385
01386
01387
01388
01389 struct heapqueue_elm *last;
01390 assert(ret!=NULL);
01391 assert(i<heap_len);
01392 assert(heap_len<NR(heap));
01393 *ret=heap[i];
01394 TRACE("canceling entry #%d: val=%d (parent=%d:>%u) (left %d:>%u) (right %d:>%u) (last %d)\n",
01395 i, ret->d,
01396 i>0 ? (int)HEAPQUEUE_PARENT(i) : -1,
01397 i>0 ? heap[HEAPQUEUE_PARENT(i)].d : 0,
01398 HEAPQUEUE_LEFT(i)<heap_len ? (int)HEAPQUEUE_LEFT(i) : -1,
01399 HEAPQUEUE_LEFT(i)<heap_len ? heap[HEAPQUEUE_LEFT(i)].d : 0,
01400 HEAPQUEUE_RIGHT(i)<heap_len ? (int)HEAPQUEUE_RIGHT(i) : -1,
01401 HEAPQUEUE_RIGHT(i)<heap_len ? heap[HEAPQUEUE_RIGHT(i)].d : 0,
01402 heap[heap_len-1].d
01403 );
01404
01405
01406 heap_len--;
01407 last=&heap[heap_len];
01408
01409
01410
01411
01412 if(i>0 && heapqueue_greaterthan(&heap[HEAPQUEUE_PARENT(i)], last)) {
01413
01414 TRACE("swap hole %d with entry %d\n", i, HEAPQUEUE_PARENT(i));
01415 heap[i]=heap[HEAPQUEUE_PARENT(i)];
01416 i=heapqueue_ll_siftup(HEAPQUEUE_PARENT(i), last);
01417 } else if(HEAPQUEUE_RIGHT(i)<heap_len && (heapqueue_greaterthan(last, &heap[HEAPQUEUE_RIGHT(i)]) || heapqueue_greaterthan(last, &heap[HEAPQUEUE_LEFT(i)]))) {
01418
01419 if(heapqueue_greaterthan(&heap[HEAPQUEUE_LEFT(i)], &heap[HEAPQUEUE_RIGHT(i)])) {
01420
01421 TRACE("swap hole %d with entry %d\n", i, HEAPQUEUE_RIGHT(i));
01422 heap[i]=heap[HEAPQUEUE_RIGHT(i)];
01423 i=heapqueue_ll_siftdown(HEAPQUEUE_RIGHT(i), last);
01424 } else {
01425
01426 TRACE("swap hole %d with entry %d\n", i, HEAPQUEUE_LEFT(i));
01427 heap[i]=heap[HEAPQUEUE_LEFT(i)];
01428 i=heapqueue_ll_siftdown(HEAPQUEUE_LEFT(i), last);
01429 }
01430 } else if(HEAPQUEUE_LEFT(i)<heap_len && heapqueue_greaterthan(last, &heap[HEAPQUEUE_LEFT(i)])) {
01431
01432 TRACE("swap hole %d with entry %d\n", i, HEAPQUEUE_LEFT(i));
01433 heap[i]=heap[HEAPQUEUE_LEFT(i)];
01434 i=heapqueue_ll_siftdown(HEAPQUEUE_LEFT(i), last);
01435 }
01436
01437 heap[i]=*last;
01438 return 1;
01439 }
01440
01447 EXPORT void heapqueue_enqueue(struct heapqueue_elm *elm) {
01448 unsigned i;
01449 assert(elm!=NULL);
01450 assert(heap_len<NR(heap));
01451
01452 i=heap_len++;
01453 i=heapqueue_ll_siftup(i, elm);
01454 heap[i]=*elm;
01455 }
01456
01461 EXPORT int heapqueue_dequeue(struct heapqueue_elm *ret) {
01462 unsigned i;
01463 assert(ret!=NULL);
01464 if(heap_len<=0)
01465 return 0;
01466 *ret=heap[0];
01467
01468
01469 heap_len--;
01470 i=heapqueue_ll_siftdown(0, &heap[heap_len]);
01471 heap[i]=heap[heap_len];
01472 return 1;
01473 }
01474
01475 #ifndef NTEST
01476
01480 static int heapqueue_isvalid(void) {
01481 unsigned i;
01482 for(i=1;i<heap_len;i++) {
01483 if(heapqueue_greaterthan(&heap[HEAPQUEUE_PARENT(i)], &heap[i])) {
01484 DEBUG("Bad heap at %d\n", i);
01485 return 0;
01486 }
01487 }
01488 return 1;
01489 }
01490
01492 static void heapqueue_dump(void) {
01493 unsigned i;
01494 fprintf(stderr, "::: Dumping heapqueue :::\n");
01495 for(i=0;i<heap_len;i++) {
01496 printf("%03u = %4u (p:%d l:%d r:%d)\n", i, heap[i].d, i>0 ? (int)HEAPQUEUE_PARENT(i) : -1, HEAPQUEUE_LEFT(i), HEAPQUEUE_RIGHT(i));
01497 }
01498 printf("heap valid? %d (%d entries)\n", heapqueue_isvalid(), heap_len);
01499 }
01500
01502 EXPORT void heapqueue_test(void) {
01503 struct heapqueue_elm elm, tmp;
01504 unsigned i;
01505 const unsigned testdata[] = {
01506 42, 2, 123, 88, 3, 3, 3, 3, 3, 1, 0,
01507 };
01508
01509
01510 heap_len=0;
01511 #ifndef NDEBUG
01512
01513 for(i=heap_len;i<NR(heap);i++) {
01514 heap[i].d=0xdead;
01515 }
01516 #endif
01517
01518 for(i=0;i<NR(testdata);i++) {
01519 elm.d=testdata[i];
01520 heapqueue_enqueue(&elm);
01521 }
01522
01523 heapqueue_dump();
01524
01525
01526 while(heap_len>0) {
01527 unsigned valid;
01528 i=rand()%heap_len;
01529 if(heapqueue_cancel(i, &tmp)) {
01530 printf("canceled at %d (data=%d)\n", i, tmp.d);
01531 } else {
01532 printf("canceled at %d failed!\n", i);
01533 break;
01534 }
01535
01536 valid=heapqueue_isvalid();
01537
01538 if(!valid) {
01539 printf("BAD HEAP!!!\n");
01540 heapqueue_dump();
01541 break;
01542 }
01543 }
01544
01545 heapqueue_dump();
01546
01547
01548 for(i=0;i<NR(testdata);i++) {
01549 elm.d=testdata[i];
01550 heapqueue_enqueue(&elm);
01551 }
01552
01553
01554 while(heapqueue_dequeue(&tmp)) {
01555 printf("removed head (data=%d)\n", tmp.d);
01556 }
01557
01558 heapqueue_dump();
01559 }
01560 #endif
01561
01562
01563
01564
01565
01567 struct freelist_extent {
01568 unsigned length, offset;
01569 };
01570
01572 struct freelist_entry {
01573 LIST_ENTRY(struct freelist_entry) global;
01574 struct freelist_extent extent;
01575 };
01576
01577 #if !defined(NTEST) || !defined(NDEBUG)
01578
01579 static void freelist_dump(struct freelist *fl) {
01580 struct freelist_entry *curr;
01581 unsigned n;
01582 fprintf(stderr, "::: Dumping freelist :::\n");
01583 for(curr=LIST_TOP(fl->global),n=0;curr;curr=LIST_NEXT(curr, global),n++) {
01584 printf("[%05u] ofs: %6d len: %6d\n", n, curr->extent.offset, curr->extent.length);
01585 }
01586 }
01587 #endif
01588
01592 static void freelist_ll_free(struct freelist_entry *e) {
01593 assert(e!=NULL);
01594 assert(e->global._prev!=NULL);
01595 assert(e->global._prev!=(void*)0x99999999);
01596 LIST_REMOVE(e, global);
01597 #ifndef NDEBUG
01598 memset(e, 0x99, sizeof *e);
01599 #endif
01600 free(e);
01601 }
01602
01606 static struct freelist_entry *freelist_ll_new(struct freelist_entry **prev, unsigned ofs, unsigned count) {
01607 struct freelist_entry *new;
01608 assert(prev!=NULL);
01609 assert(prev!=(void*)0x99999999);
01610 new=malloc(sizeof *new);
01611 assert(new!=NULL);
01612 if(!new) {
01613 PERROR("malloc()");
01614 return 0;
01615 }
01616 new->extent.offset=ofs;
01617 new->extent.length=count;
01618 LIST_INSERT_ATPTR(prev, new, global);
01619 return new;
01620 }
01621
01626 static int freelist_ll_isbridge(struct freelist_extent *prev_ext, unsigned ofs, unsigned count, struct freelist_extent *next_ext) {
01627
01628
01629
01630
01631
01632
01633
01634 return prev_ext->offset+prev_ext->length==ofs && next_ext->offset==ofs+count;
01635 }
01636
01638 void freelist_init(struct freelist *fl) {
01639 LIST_INIT(&fl->global);
01640 }
01641
01643 void freelist_free(struct freelist *fl) {
01644 while(LIST_TOP(fl->global)) {
01645 freelist_ll_free(LIST_TOP(fl->global));
01646 }
01647 assert(LIST_TOP(fl->global)==NULL);
01648 }
01649
01653 long freelist_alloc(struct freelist *fl, unsigned count) {
01654 struct freelist_entry *curr;
01655
01656 for(curr=LIST_TOP(fl->global);curr;curr=LIST_NEXT(curr, global)) {
01657 if(curr->extent.length>=count) {
01658 unsigned ofs;
01659 ofs=curr->extent.offset;
01660 curr->extent.offset+=count;
01661 curr->extent.length-=count;
01662 if(curr->extent.length==0) {
01663 freelist_ll_free(curr);
01664 }
01665 return ofs;
01666 }
01667 }
01668 return -1;
01669 }
01670
01684 void freelist_pool(struct freelist *fl, unsigned ofs, unsigned count) {
01685 struct freelist_entry *new, *curr, *last;
01686
01687 TRACE_ENTER();
01688
01689 assert(count!=0);
01690
01691 last=NULL;
01692 new=NULL;
01693 for(curr=LIST_TOP(fl->global);curr;curr=LIST_NEXT(curr, global)) {
01694 assert(curr!=last);
01695 assert(curr!=(void*)0x99999999);
01696 if(last) {
01697 assert(LIST_NEXT(last, global)==curr);
01698 }
01699
01700
01701
01702
01703
01704
01705
01706
01707
01708 if(ofs==curr->extent.offset) {
01709 ERROR_FMT("overlap detected in freelist %p at %u+%u!\n", (void*)fl, ofs, count);
01710 TODO("make something out of this");
01711 DIE();
01712 } else if(last && freelist_ll_isbridge(&last->extent, ofs, count, &curr->extent)) {
01713
01714 DEBUG("|......|XXX|.......| bridge. last=%u+%u curr=%u+%u new=%u+%u\n", last->extent.length, last->extent.offset, curr->extent.offset, curr->extent.length, ofs, count);
01715
01716
01717 last->extent.length+=curr->extent.length+count;
01718 assert(LIST_PREVPTR(curr, global)==&LIST_NEXT(last, global));
01719 freelist_ll_free(curr);
01720 assert(LIST_TOP(fl->global)!=curr);
01721 assert(LIST_NEXT(last, global)!=(void*)0x99999999);
01722 assert(LIST_NEXT(last, global)!=curr);
01723 new=curr=last;
01724 break;
01725 } else if(curr->extent.offset==ofs+count) {
01726
01727 DEBUG("|.....|_XXX|.......| grow-next. curr=%u+%u new=%u+%u\n", curr->extent.offset, curr->extent.length, ofs, count);
01728
01729 curr->extent.offset=ofs;
01730 curr->extent.length+=count;
01731 new=curr;
01732 break;
01733 } else if(last && curr->extent.offset+curr->extent.length==ofs) {
01734
01735 DEBUG("|......|XXX_|......| grow-prev. curr=%u+%u new=%u+%u\n", curr->extent.offset, curr->extent.length, ofs, count);
01736
01737 curr->extent.length+=count;
01738 new=curr;
01739 break;
01740 } else if(ofs<curr->extent.offset) {
01741 if(ofs+count>curr->extent.offset) {
01742 ERROR_FMT("overlap detected in freelist %p at %u+%u!\n", (void*)fl, ofs, count);
01743 TODO("make something out of this");
01744 DIE();
01745 }
01746 DEBUG("|.....|_XXX_|......| normal new=%u+%u\n", ofs, count);
01747
01748 new=freelist_ll_new(LIST_PREVPTR(curr, global), ofs, count);
01749 break;
01750 }
01751
01752 last=curr;
01753 }
01754 if(!curr) {
01755 if(last) {
01756 if(last->extent.offset+last->extent.length==ofs) {
01757 DEBUG("|......|XXX_|......| grow-prev. last=%u+%u new=%u+%u\n", last->extent.offset, last->extent.length, ofs, count);
01758 last->extent.length+=count;
01759 new=last;
01760 } else {
01761 DEBUG("|............|XXX | end. new=%u+%u\n", ofs, count);
01762 new=freelist_ll_new(&LIST_NEXT(last, global), ofs, count);
01763 }
01764 } else {
01765 DEBUG("|XXX | initial. new=%u+%u\n", ofs, count);
01766 new=freelist_ll_new(&LIST_TOP(fl->global), ofs, count);
01767 }
01768 }
01769 }
01770
01776 int freelist_thwack(struct freelist *fl, unsigned ofs, unsigned count) {
01777 struct freelist_entry *curr;
01778
01779 assert(count!=0);
01780
01781 DEBUG("thwacking %u:%u\n", ofs, count);
01782
01783 #ifndef NDEBUG
01784 freelist_dump(fl);
01785 #endif
01786 for(curr=LIST_TOP(fl->global);curr;curr=LIST_NEXT(curr, global)) {
01787 DEBUG("checking for %u:%u in curr=%u:%u\n", ofs, count, curr->extent.offset, curr->extent.length);
01788 if(curr->extent.offset<=ofs && curr->extent.offset+curr->extent.length>=ofs+count) {
01789 TRACE("Found entry to thwack at %u:%u for %u:%u\n", curr->extent.offset, curr->extent.length, ofs, count);
01790
01791
01792
01793
01794
01795
01796
01797 if(curr->extent.offset==ofs && curr->extent.length==count) {
01798
01799 freelist_ll_free(curr);
01800 return 1;
01801 } else if(curr->extent.offset==ofs) {
01802
01803 curr->extent.offset+=count;
01804 curr->extent.length-=count;
01805 return 1;
01806 } else if((curr->extent.offset+curr->extent.length)==(ofs+count)) {
01807
01808 curr->extent.length-=count;
01809 return 1;
01810 } else {
01811 struct freelist_extent new;
01812
01813
01814
01815
01816 new.offset=ofs+count;
01817 new.length=(curr->extent.offset+curr->extent.length)-new.offset;
01818 DEBUG("ofs=%d curr.offset=%d\n", ofs, curr->extent.offset);
01819 assert(curr->extent.length >= count+new.length);
01820 curr->extent.length-=count;
01821 curr->extent.length-=new.length;
01822 freelist_pool(fl, new.offset, new.length);
01823 return 1;
01824 }
01825 DEBUG_MSG("Should not be possible to get here");
01826 DIE();
01827 }
01828 }
01829 DEBUG_MSG("failed.");
01830 return 0;
01831 }
01832
01833 #ifndef NTEST
01834
01835 EXPORT void freelist_test(void) {
01836 struct freelist fl;
01837 unsigned n;
01838 freelist_init(&fl);
01839 fprintf(stderr, "::: Making some fragments :::\n");
01840 for(n=0;n<60;n+=12) {
01841 freelist_pool(&fl, n, 6);
01842 }
01843 fprintf(stderr, "::: Filling in gaps :::\n");
01844 for(n=0;n<60;n+=12) {
01845 freelist_pool(&fl, n+6, 6);
01846 }
01847 fprintf(stderr, "::: Walking backwards :::\n");
01848 for(n=120;n>60;) {
01849 n-=6;
01850 freelist_pool(&fl, n, 6);
01851 }
01852
01853 freelist_dump(&fl);
01854
01855
01856 fprintf(stderr, "::: Allocating :::\n");
01857 for(n=0;n<60;n+=6) {
01858 long ofs;
01859 ofs=freelist_alloc(&fl, 6);
01860 TRACE("alloc: %lu+%u\n", ofs, 6);
01861 }
01862
01863 freelist_dump(&fl);
01864
01865 fprintf(stderr, "::: Allocating :::\n");
01866 for(n=0;n<60;n+=6) {
01867 long ofs;
01868 ofs=freelist_alloc(&fl, 6);
01869 TRACE("alloc: %lu+%u\n", ofs, 6);
01870 }
01871
01872 freelist_dump(&fl);
01873 fprintf(stderr, "<freelist should be empty>\n");
01874
01875 freelist_pool(&fl, 1003, 1015);
01876
01877 freelist_dump(&fl);
01878
01879 freelist_thwack(&fl, 1007, 1005);
01880
01881 freelist_thwack(&fl, 2012, 6);
01882
01883 freelist_thwack(&fl, 1003, 4);
01884
01885 freelist_dump(&fl);
01886 fprintf(stderr, "<freelist should be empty>\n");
01887
01888 freelist_free(&fl);
01889 }
01890 #endif
01891
01892
01893
01894
01895
01896
01898 static FILE *eventlog_file;
01899
01900
01901
01902
01903
01907 EXPORT int eventlog_init(void) {
01908 eventlog_file=fopen(mud_config.eventlog_filename, "a");
01909 if(!eventlog_file) {
01910 PERROR(mud_config.eventlog_filename);
01911 return 0;
01912 }
01913
01914 setvbuf(eventlog_file, NULL, _IOLBF, 0);
01915
01916 return 1;
01917 }
01918
01920 EXPORT void eventlog_shutdown(void) {
01921 if(eventlog_file) {
01922 fclose(eventlog_file);
01923 eventlog_file=0;
01924 }
01925 }
01926
01928 EXPORT void eventlog(const char *type, const char *fmt, ...) {
01929 va_list ap;
01930 char buf[512];
01931 int n;
01932 time_t t;
01933 char timestamp[64];
01934
01935 va_start(ap, fmt);
01936 n=vsnprintf(buf, sizeof buf, fmt, ap);
01937 va_end(ap);
01938 if(n<0) {
01939 ERROR_MSG("vsnprintf() failure");
01940 return;
01941 }
01942
01943 if(n>=(int)sizeof buf) {
01944 n=strlen(buf);
01945 }
01946
01947
01948 if(n>0 && buf[n-1]!='\n') {
01949 if(n==sizeof buf) n--;
01950 buf[n]='\n';
01951 buf[n+1]=0;
01952 DEBUG_MSG("Adding newline to message");
01953 }
01954
01955 time(&t);
01956 strftime(timestamp, sizeof timestamp, mud_config.eventlog_timeformat, gmtime(&t));
01957 if(fprintf(eventlog_file?eventlog_file:stderr, "%s:%s:%s", timestamp, type, buf)<0) {
01958
01959 PERROR(eventlog_file?mud_config.eventlog_filename:"stderr");
01960 }
01961 }
01962
01966 EXPORT void eventlog_connect(const char *peer_str) {
01967 eventlog("CONNECT", "remote=%s\n", peer_str);
01968 }
01969
01971 EXPORT void eventlog_server_startup(void) {
01972 eventlog("STARTUP", "\n");
01973 }
01974
01976 EXPORT void eventlog_server_shutdown(void) {
01977 eventlog("SHUTDOWN", "\n");
01978 }
01979
01981 EXPORT void eventlog_login_failattempt(const char *username, const char *peer_str) {
01982 eventlog("LOGINFAIL", "remote=%s name='%s'\n", peer_str, username);
01983 }
01984
01986 EXPORT void eventlog_signon(const char *username, const char *peer_str) {
01987 eventlog("SIGNON", "remote=%s name='%s'\n", peer_str, username);
01988 }
01989
01991 EXPORT void eventlog_signoff(const char *username, const char *peer_str) {
01992 eventlog("SIGNOFF", "remote=%s name='%s'\n", peer_str, username);
01993 }
01994
01996 EXPORT void eventlog_toomany(void) {
01998 eventlog("TOOMANY", "\n");
01999 }
02000
02004 EXPORT void eventlog_commandinput(const char *remote, const char *username, const char *line) {
02005 eventlog("COMMAND", "remote=\"%s\" user=\"%s\" command=\"%s\"\n", remote, username, line);
02006 }
02007
02009 EXPORT void eventlog_channel_new(const char *channel_name) {
02010 eventlog("CHANNEL-NEW", "channel=\"%s\"\n", channel_name);
02011 }
02012
02014 EXPORT void eventlog_channel_remove(const char *channel_name) {
02015 eventlog("CHANNEL-REMOVE", "channel=\"%s\"\n", channel_name);
02016 }
02017
02019 EXPORT void eventlog_channel_join(const char *remote, const char *channel_name, const char *username) {
02020 if(!remote) {
02021 eventlog("CHANNEL-JOIN", "channel=\"%s\" user=\"%s\"\n", channel_name, username);
02022 } else {
02023 eventlog("CHANNEL-JOIN", "remote=\"%s\" channel=\"%s\" user=\"%s\"\n", remote, channel_name, username);
02024 }
02025 }
02026
02028 EXPORT void eventlog_channel_part(const char *remote, const char *channel_name, const char *username) {
02029 if(!remote) {
02030 eventlog("CHANNEL-PART", "channel=\"%s\" user=\"%s\"\n", channel_name, username);
02031 } else {
02032 eventlog("CHANNEL-PART", "remote=\"%s\" channel=\"%s\" user=\"%s\"\n", remote, channel_name, username);
02033 }
02034 }
02035
02039 EXPORT void eventlog_webserver_get(const char *remote, const char *uri) {
02040 eventlog("WEBSITE-GET", "remote=\"%s\" uri=\"%s\"\n", remote?remote:"", uri?uri:"");
02041 }
02042
02043
02044
02045
02046 struct config_watcher;
02047
02049 struct config {
02050 LIST_HEAD(struct, struct config_watcher) watchers;
02051 };
02052
02054 struct config_watcher {
02055 LIST_ENTRY(struct config_watcher) list;
02056 char *mask;
02057 int (*func)(struct config *cfg, void *extra, const char *id, const char *value);
02058 void *extra;
02059 };
02060
02062 EXPORT void config_setup(struct config *cfg) {
02063 LIST_INIT(&cfg->watchers);
02064 }
02065
02067 EXPORT void config_free(struct config *cfg) {
02068 struct config_watcher *curr;
02069 assert(cfg != NULL);
02070 while((curr=LIST_TOP(cfg->watchers))) {
02071 LIST_REMOVE(curr, list);
02072 free(curr->mask);
02073 free(curr);
02074 }
02075 }
02076
02081 EXPORT void config_watch(struct config *cfg, const char *mask, int (*func)(struct config *cfg, void *extra, const char *id, const char *value), void *extra) {
02082 struct config_watcher *w;
02083 assert(mask != NULL);
02084 assert(cfg != NULL);
02085 w=malloc(sizeof *w);
02086 w->mask=strdup(mask);
02087 w->func=func;
02088 w->extra=extra;
02089 LIST_INSERT_HEAD(&cfg->watchers, w, list);
02090 }
02091
02093 EXPORT int config_load(const char *filename, struct config *cfg) {
02094 char buf[1024];
02095 FILE *f;
02096 char *e, *value;
02097 unsigned line;
02098 char quote;
02099 struct config_watcher *curr;
02100
02101 f=fopen(filename, "r");
02102 if(!f) {
02103 PERROR(filename);
02104 return 0;
02105 }
02106 line=0;
02107 while(line++,fgets(buf, sizeof buf, f)) {
02108
02109 for(e=buf,quote=0;*e;e++) {
02110 if(!quote && *e=='"')
02111 quote=*e;
02112 else if(!quote && *e=='\'')
02113 quote=*e;
02114 else if(quote=='\'' && *e=='\'')
02115 quote=0;
02116 else if(quote=='"' && *e=='"')
02117 quote=0;
02118 else if(!quote && ( *e=='#' || (*e=='/' && e[1]=='/' ))) {
02119 *e=0;
02120 break;
02121 }
02122 }
02123
02124
02125 e=buf+strlen(buf);
02126 while(e>buf && isspace(*--e)) {
02127 *e=0;
02128 }
02129
02130
02131 if(*buf==0) {
02132 TRACE("%s:%d:ignoring blank line\n", filename, line);
02133 continue;
02134 }
02135
02136 e=strchr(buf, '=');
02137 if(!e) {
02138
02139 ERROR_FMT("%s:%d:invalid directive\n", filename, line);
02140 goto failure;
02141 }
02142
02143
02144 value=e+1;
02145 while(isspace(*value)) value++;
02146
02147
02148 *e=0;
02149 while(e>buf && isspace(*--e)) {
02150 *e=0;
02151 }
02152
02153 if(*value=='"') {
02154 value++;
02155 e=strchr(value, '"');
02156 if(e) {
02157 if(e[1]) {
02158 ERROR_FMT("%s:%u:error in loading file:trailing garbage after quote\n", filename, line);
02159 goto failure;
02160 }
02161 *e=0;
02162 } else {
02163 ERROR_FMT("%s:%u:error in loading file:missing quote\n", filename, line);
02164 goto failure;
02165 }
02166 }
02167
02168 DEBUG("id='%s' value='%s'\n", buf, value);
02169
02170
02171 for(curr=LIST_TOP(cfg->watchers);curr;curr=LIST_NEXT(curr, list)) {
02172 if(!util_fnmatch(curr->mask, buf, UTIL_FNM_CASEFOLD) && curr->func) {
02173 int res;
02174 res=curr->func(cfg, curr->extra, buf, value);
02175 if(!res) {
02176 break;
02177 } else if(res<0) {
02178 ERROR_FMT("%s:%u:error in loading file\n", filename, line);
02179 goto failure;
02180 }
02181 }
02182 }
02183 }
02184 fclose(f);
02185 return 1;
02186 failure:
02187 fclose(f);
02188 return 0;
02189 }
02190
02191 #ifndef NTEST
02192
02193 static int config_test_show(struct config *cfg UNUSED, void *extra UNUSED, const char *id, const char *value) {
02194 printf("CONFIG SHOW: %s=%s\n", id, value);
02195 return 1;
02196 }
02197
02199 static void config_test(void) {
02200 struct config cfg;
02201 config_setup(&cfg);
02202 config_watch(&cfg, "s*er.*", config_test_show, 0);
02203 config_load("test.cfg", &cfg);
02204 config_free(&cfg);
02205 }
02206 #endif
02207
02208
02209
02210
02211
02213 #define BITMAP_BITSIZE (sizeof(unsigned)*CHAR_BIT)
02214
02221 struct bitmap {
02222 unsigned *bitmap;
02223 size_t bitmap_allocbits;
02224 };
02225
02229 EXPORT void bitmap_init(struct bitmap *bitmap) {
02230 assert(bitmap!=NULL);
02231 bitmap->bitmap=0;
02232 bitmap->bitmap_allocbits=0;
02233 }
02234
02238 EXPORT void bitmap_free(struct bitmap *bitmap) {
02239 assert(bitmap!=NULL);
02240 if(bitmap) {
02241 free(bitmap->bitmap);
02242 bitmap_init(bitmap);
02243 }
02244 }
02245
02251 EXPORT int bitmap_resize(struct bitmap *bitmap, size_t newbits) {
02252 unsigned *tmp;
02253
02254 newbits=ROUNDUP(newbits, BITMAP_BITSIZE);
02255 DEBUG("Allocating %zd bytes\n", newbits/CHAR_BIT);
02256 tmp=realloc(bitmap->bitmap, newbits/CHAR_BIT);
02257 if(!tmp) {
02258 PERROR("realloc()");
02259 return 0;
02260 }
02261 if(bitmap->bitmap_allocbits<newbits) {
02262
02263 size_t len;
02264 len=(newbits-bitmap->bitmap_allocbits)/CHAR_BIT;
02265 DEBUG("Clearing %zd bytes (ofs %zd)\n", len, bitmap->bitmap_allocbits/BITMAP_BITSIZE);
02266 memset(tmp+bitmap->bitmap_allocbits/BITMAP_BITSIZE, 0, len);
02267 }
02268
02269 bitmap->bitmap=tmp;
02270 bitmap->bitmap_allocbits=newbits;
02271 return 1;
02272 }
02273
02280 EXPORT void bitmap_clear(struct bitmap *bitmap, unsigned ofs, unsigned len) {
02281 unsigned *p, mask;
02282 unsigned head_ofs, head_len;
02283
02284
02285 if(ofs+len>bitmap->bitmap_allocbits) {
02286 bitmap_resize(bitmap, ofs+len);
02287 }
02288
02289 p=bitmap->bitmap+ofs/BITMAP_BITSIZE;
02290
02291 head_ofs=ofs%BITMAP_BITSIZE;
02292 head_len=len>BITMAP_BITSIZE-ofs ? BITMAP_BITSIZE-ofs : len;
02293
02294
02295 if(head_len<BITMAP_BITSIZE) {
02296 len-=head_len;
02297 mask=~(~((~0U)<<head_len)<<head_ofs);
02298 *p++&=mask;
02299 }
02300
02301 for(;len>=BITMAP_BITSIZE;len-=BITMAP_BITSIZE) {
02302 *p++=0U;
02303 }
02304
02305 if(len>0) {
02306
02307 mask=~((~0U)>>(BITMAP_BITSIZE-len));
02308 mask=(~0U)>>len;
02309 *p&=mask;
02310 }
02311 }
02312
02319 EXPORT void bitmap_set(struct bitmap *bitmap, unsigned ofs, unsigned len) {
02320 unsigned *p, mask;
02321 unsigned head_ofs, head_len;
02322
02323
02324 if(ofs+len>bitmap->bitmap_allocbits) {
02325 bitmap_resize(bitmap, ofs+len);
02326 }
02327
02328 p=bitmap->bitmap+ofs/BITMAP_BITSIZE;
02329
02330 head_ofs=ofs%BITMAP_BITSIZE;
02331 head_len=len>BITMAP_BITSIZE-ofs ? BITMAP_BITSIZE-ofs : len;
02332
02333
02334 if(head_len<BITMAP_BITSIZE) {
02335 len-=head_len;
02336 mask=(~((~0U)<<head_len))<<head_ofs;
02337 *p++|=mask;
02338 }
02339
02340 for(;len>=BITMAP_BITSIZE;len-=BITMAP_BITSIZE) {
02341 *p++=~0U;
02342 }
02343
02344 if(len>0) {
02345
02346 mask=(~0U)>>(BITMAP_BITSIZE-len);
02347 *p|=mask;
02348 }
02349 }
02350
02357 EXPORT int bitmap_get(struct bitmap *bitmap, unsigned ofs) {
02358 if(ofs<bitmap->bitmap_allocbits) {
02359 return (bitmap->bitmap[ofs/BITMAP_BITSIZE]>>(ofs%BITMAP_BITSIZE))&1;
02360 } else {
02361 return 0;
02362 }
02363 }
02364
02371 EXPORT int bitmap_next_set(struct bitmap *bitmap, unsigned ofs) {
02372 unsigned i, len, bofs;
02373 assert(bitmap != NULL);
02374 len=bitmap->bitmap_allocbits/BITMAP_BITSIZE;
02375 TODO("check the head");
02376 for(i=ofs/BITMAP_BITSIZE;i<len;i++) {
02377 if(bitmap->bitmap[i]!=0) {
02378
02379 for(bofs=0;((bitmap->bitmap[i]>>bofs)&1)==0;bofs++) ;
02380 return i*BITMAP_BITSIZE+bofs;
02381 }
02382 }
02383 TODO("check the tail");
02384 return -1;
02385 }
02386
02393 EXPORT int bitmap_next_clear(struct bitmap *bitmap, unsigned ofs) {
02394 unsigned i, len, bofs;
02395 assert(bitmap != NULL);
02396 len=bitmap->bitmap_allocbits/BITMAP_BITSIZE;
02397 TODO("check the head");
02398 for(i=ofs/BITMAP_BITSIZE;i<len;i++) {
02399 if(bitmap->bitmap[i]!=~0U) {
02400
02401 for(bofs=0;((bitmap->bitmap[i]>>bofs)&1)==1;bofs++) ;
02402 return i*BITMAP_BITSIZE+bofs;
02403 }
02404 }
02405 TODO("check the tail");
02406 return -1;
02407 }
02408
02416 EXPORT void bitmap_loadmem(struct bitmap *bitmap, unsigned char *d, size_t len) {
02417 unsigned *p, word_count, i;
02418
02419
02420 if((len*CHAR_BIT)>bitmap->bitmap_allocbits) {
02421 bitmap_resize(bitmap, len*CHAR_BIT);
02422 }
02423
02424 p=bitmap->bitmap;
02425 word_count=len/sizeof *p;
02426
02427
02428 while(word_count>0) {
02429 i=sizeof *p-1;
02430 *p=0;
02431 do {
02432 *p|=*d<<(i*CHAR_BIT);
02433 d++;
02434 } while(--i);
02435 p++;
02436 word_count--;
02437 len-=sizeof *p;
02438 }
02439
02440
02441 i=sizeof *p-1;
02442 while(len>0) {
02443 *p&=0xff<<(i*CHAR_BIT);
02444 *p|=*d<<(i*CHAR_BIT);
02445 i--;
02446 d++;
02447 len--;
02448 }
02449 }
02450
02455 EXPORT unsigned bitmap_length(struct bitmap *bitmap) {
02456 return bitmap ? ROUNDUP(bitmap->bitmap_allocbits, CHAR_BIT)/CHAR_BIT : 0;
02457 }
02458
02459 #ifndef NTEST
02460
02463 EXPORT void bitmap_test(void) {
02464 int i;
02465 struct bitmap bitmap;
02466
02467 bitmap_init(&bitmap);
02468 bitmap_resize(&bitmap, 1024);
02469
02470 for(i=0;i<5;i++) {
02471 bitmap.bitmap[i]=0x12345678;
02472 }
02473
02474 bitmap_set(&bitmap, 7, 1);
02475
02476 printf("bitmap_set():\n");
02477 for(i=0;i<5;i++) {
02478 printf("0x%08x %s\n", bitmap.bitmap[i], util_convertnumber(bitmap.bitmap[i], 2, 32));
02479 }
02480
02481 bitmap_set(&bitmap, 12, 64);
02482
02483 printf("bitmap_set():\n");
02484 for(i=0;i<5;i++) {
02485 printf("0x%08x %s\n", bitmap.bitmap[i], util_convertnumber(bitmap.bitmap[i], 2, 32));
02486 }
02487
02488 bitmap_clear(&bitmap, 7, 1);
02489
02490 printf("bitmap_clear():\n");
02491 for(i=0;i<5;i++) {
02492 printf("0x%08x %s\n", bitmap.bitmap[i], util_convertnumber(bitmap.bitmap[i], 2, 32));
02493 }
02494
02495 bitmap_clear(&bitmap, 12, 64);
02496
02497 printf("bitmap_clear():\n");
02498 for(i=0;i<5;i++) {
02499 printf("0x%08x %s\n", bitmap.bitmap[i], util_convertnumber(bitmap.bitmap[i], 2, 32));
02500 }
02501
02502 bitmap_set(&bitmap, 0, BITMAP_BITSIZE*5);
02503
02504 printf("bitmap_set():\n");
02505 for(i=0;i<5;i++) {
02506 printf("0x%08x %s\n", bitmap.bitmap[i], util_convertnumber(bitmap.bitmap[i], 2, 32));
02507 }
02508
02509 bitmap_clear(&bitmap, 0, BITMAP_BITSIZE*5);
02510 bitmap_set(&bitmap, 101, 1);
02511 printf("word at bit 101 = 0x%08x\n", bitmap.bitmap[101/BITMAP_BITSIZE]);
02512 printf("next set starting at 9 = %d\n", bitmap_next_set(&bitmap, 9));
02513 bitmap_clear(&bitmap, 101, 1);
02514
02515 bitmap_set(&bitmap, 0, 101);
02516 printf("next clear starting at 9 = %d\n", bitmap_next_clear(&bitmap, 9));
02517 bitmap_clear(&bitmap, 0, 101);
02518
02519 bitmap_clear(&bitmap, 0, BITMAP_BITSIZE*5);
02520 printf("next set should return -1 = %d\n", bitmap_next_set(&bitmap, 0));
02521
02522 bitmap_free(&bitmap);
02523 }
02524 #endif
02525
02526
02527
02528
02529 #include <limits.h>
02530
02532 struct acs_info {
02533 unsigned char level;
02534 unsigned flags;
02535 };
02536
02538 static void acs_init(struct acs_info *ai, unsigned level, unsigned flags) {
02539 ai->level=level<=UCHAR_MAX?level:UCHAR_MAX;
02540 ai->flags=flags;
02541 }
02542
02544 static int acs_testflag(struct acs_info *ai, unsigned flag) {
02545 unsigned i;
02546 flag=tolower((char)flag);
02547 if(flag>='a' && flag<='z') {
02548 i=flag-'a';
02549 } else if(flag>='0' && flag<='9') {
02550 i=flag-'0'+26;
02551 } else {
02552 ERROR_FMT("unknown flag '%c'\n", flag);
02553 return 0;
02554 }
02555 return ((ai->flags>>i)&1)==1;
02556 }
02557
02559 static int acs_check(struct acs_info *ai, const char *acsstring) {
02560 const char *s=acsstring;
02561 const char *endptr;
02562 unsigned long level;
02563 retry:
02564 while(*s) switch(*s++) {
02565 case 's':
02566 level=strtoul(s, (char**)&endptr, 10);
02567 if(endptr==acsstring) {
02568 goto parse_failure;
02569 }
02570 if(ai->level<level) goto did_not_pass;
02571 s=endptr;
02572 break;
02573 case 'f':
02574 if(!acs_testflag(ai, (unsigned)*s)) goto did_not_pass;
02575 s++;
02576 break;
02577 case '|':
02578 return 1;
02579 default:
02580 goto parse_failure;
02581 }
02582 return 1;
02583 did_not_pass:
02584 while(*s) if(*s++=='|') goto retry;
02585 return 0;
02586 parse_failure:
02587 ERROR_FMT("acs parser failure '%s' (off=%td)\n", acsstring, s-acsstring);
02588 return 0;
02589 }
02590
02591 #ifndef NTEST
02592
02594 void acs_test(void) {
02595 struct acs_info ai_test;
02596
02597 acs_init(&ai_test, 4, 0);
02598
02599 printf("acs_check() %d\n", acs_check(&ai_test, "s6fA"));
02600 printf("acs_check() %d\n", acs_check(&ai_test, "s2"));
02601 printf("acs_check() %d\n", acs_check(&ai_test, "s2fA"));
02602 printf("acs_check() %d\n", acs_check(&ai_test, "s8|s2"));
02603 }
02604 #endif
02605
02606
02607
02608
02612 #define IAC '\377'
02613
02615 #define DONT '\376'
02616
02618 #define DO '\375'
02619
02621 #define WONT '\374'
02622
02624 #define WILL '\373'
02625
02627 #define SB '\372'
02628
02630 #define GA '\371'
02631
02633 #define EL '\370'
02634
02636 #define EC '\367'
02637
02639 #define AYT '\366'
02640
02642 #define AO '\365'
02643
02645 #define IP '\364'
02646
02648 #define BREAK '\363'
02649
02651 #define DM '\362'
02652
02654 #define NOP '\361'
02655
02657 #define SE '\360'
02658
02660 #define EOR '\357'
02661
02663 #define ABORT '\356'
02664
02666 #define SUSP '\355'
02667
02669 #define xEOF '\354'
02670
02672 #define SYNCH '\362'
02673
02674
02675
02677 #define TELOPT_ECHO 1
02678
02680 #define TELOPT_SGA 3
02681
02683 #define TELOPT_TTYPE 24
02684
02686 #define TELOPT_NAWS 31
02687
02689 #define TELOPT_LINEMODE 34
02690
02691
02692
02694 #define TELQUAL_IS 0
02695
02697 #define TELQUAL_SEND 1
02698
02700 #define TELQUAL_INFO 2
02701
02702
02703
02705 #define LM_MODE 1
02706
02708 #define LM_FORWARDMASK 2
02709
02711 #define LM_SLC 3
02712
02713
02714
02716 #define MODE_EDIT 1
02717
02719 #define MODE_TRAPSIG 2
02720
02722 #define MODE_ACK 4
02723
02725 #define MODE_SOFT_TAB 8
02726
02728 #define MODE_LIT_ECHO 16
02729
02731 #define MODE_MASK 31
02732
02733
02734
02735
02736
02737 static const uint8_t base64enc_tab[64]= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
02738 static uint8_t *base64dec_tab;
02739
02744 EXPORT int base64_encode(size_t in_len, const unsigned char *in, size_t out_len, char *out) {
02745 unsigned ii, io;
02746 uint_least32_t v;
02747 unsigned rem;
02748
02749 for(io=0,ii=0,v=0,rem=0;ii<in_len;ii++) {
02750 unsigned char ch;
02751 ch=in[ii];
02752 v=(v<<8)|ch;
02753 rem+=8;
02754 while(rem>=6) {
02755 rem-=6;
02756 if(io>=out_len) return -1;
02757 out[io++]=base64enc_tab[(v>>rem)&63];
02758 }
02759 }
02760 if(rem) {
02761 v<<=(6-rem);
02762 if(io>=out_len) return -1;
02763 out[io++]=base64enc_tab[v&63];
02764 }
02765 while(io&3) {
02766 if(io>=out_len) return -1;
02767 out[io++]='=';
02768 }
02769 if(io>=out_len) return -1;
02770 out[io]=0;
02771 return io;
02772 }
02773
02774
02775 EXPORT int base64_decode(size_t in_len, const char *in, size_t out_len, unsigned char *out) {
02776 unsigned ii, io;
02777 uint_least32_t v;
02778 unsigned rem;
02779
02780
02781 if(!base64dec_tab) {
02782 unsigned i;
02783 base64dec_tab=malloc(256);
02784 if(!base64dec_tab) {
02785 PERROR("malloc()");
02786 return 0;
02787 }
02788 memset(base64dec_tab, 255, 256);
02790 for(i=0;i<NR(base64enc_tab);i++) {
02791 base64dec_tab[base64enc_tab[i]]=i;
02792 }
02793 }
02794
02795 for(io=0,ii=0,v=0,rem=0;ii<in_len;ii++) {
02796 unsigned char ch;
02797 if(isspace(in[ii])) continue;
02798 if(in[ii]=='=') break;
02799 ch=base64dec_tab[(unsigned)in[ii]];
02800 if(ch==255) break;
02801 v=(v<<6)|ch;
02802 rem+=6;
02803 if(rem>=8) {
02804 rem-=8;
02805 if(io>=out_len) return -1;
02806 out[io++]=(v>>rem)&255;
02807 }
02808 }
02809 if(rem>=8) {
02810 rem-=8;
02811 if(io>=out_len) return -1;
02812 out[io++]=(v>>rem)&255;
02813 }
02814 return io;
02815 }
02816
02817
02818
02819
02820
02821
02822
02823
02824
02825
02826
02827 #include <assert.h>
02828 #include <stdio.h>
02829 #include <string.h>
02830 #include <stdint.h>
02831
02835 #define SHA1_DIGEST_LENGTH 20
02836
02840 #define SHA1_LBLOCK 16
02841
02845 #define SHA1_K0 0x5a827999
02846 #define SHA1_K1 0x6ed9eba1
02847 #define SHA1_K2 0x8f1bbcdc
02848 #define SHA1_K3 0xca62c1d6
02849
02854 #define ROL(f, v, b) ((((v)<<(b))|((v)>>((f)-(b))))&(0xfffffffful>>(32-(f))))
02855
02856
02857
02858 #define ROL32(v, b) ROL(32, v, b)
02859
02863 struct sha1_ctx {
02864 uint_least32_t
02865 h[5],
02866 data[SHA1_LBLOCK];
02867 uint_least64_t cnt;
02868 unsigned data_len;
02869 };
02870
02874 EXPORT int sha1_init(struct sha1_ctx *ctx) {
02875 if(!ctx) return 0;
02876
02877
02878 ctx->h[0]=0x67452301lu;
02879 ctx->h[1]=0xefcdab89lu;
02880 ctx->h[2]=0x98badcfelu;
02881 ctx->h[3]=0x10325476lu;
02882 ctx->h[4]=0xc3d2e1f0lu;
02883
02884 ctx->cnt=0;
02885 ctx->data_len=0;
02886 memset(ctx->data, 0, sizeof ctx->data);
02887
02888 return 1;
02889 }
02890
02894 static void sha1_transform_chunk(struct sha1_ctx *ctx) {
02895 unsigned i;
02896 uint_least32_t
02897 v[5],
02898 f, k, tmp, w[16];
02899
02900 assert(ctx != NULL);
02901
02902
02903 for(i=0;i<5;i++) {
02904 v[i]=ctx->h[i];
02905 }
02906
02907 for(i=0;i<80;i++) {
02908 unsigned t=i&15;
02909
02910 if(i<16) {
02911
02912 w[i]=ctx->data[i];
02913 } else {
02914
02915 w[t]^=w[(t+13)&15]^w[(t+8)&15]^w[(t+2)&15];
02916 w[t]=ROL32(w[t], 1);
02917 }
02918
02919 if(i<20) {
02920 f=(v[1]&v[2])|(~v[1]&v[3]);
02921 k=SHA1_K0;
02922 } else if(i<40) {
02923 f=v[1]^v[2]^v[3];
02924 k=SHA1_K1;
02925 } else if(i<60) {
02926 f=(v[1]&v[2])|(v[1]&v[3])|(v[2]&v[3]);
02927 k=SHA1_K2;
02928 } else {
02929 f=v[1]^v[2]^v[3];
02930 k=SHA1_K3;
02931 }
02932
02933 tmp=ROL32(v[0], 5);
02934 tmp+=f+v[4]+k+w[t];
02935 v[4]=v[3];
02936 v[3]=v[2];
02937 v[2]=ROL32(v[1], 30);
02938 v[1]=v[0];
02939 v[0]=tmp;
02940
02941 }
02942
02943
02944 for(i=0;i<5;i++) {
02945 ctx->h[i]+=v[i];
02946 }
02947
02948 memset(v, 0, sizeof v);
02949 }
02950
02954 EXPORT int sha1_update(struct sha1_ctx *ctx, const void *data, size_t len) {
02955 if(!ctx||(!data&&!len)) return 0;
02956
02957 while(len>0) {
02958
02959
02960
02961
02962 while(ctx->data_len<4*SHA1_LBLOCK) {
02963 if(len<=0) return 1;
02964
02965
02966 switch((ctx->cnt/8)%4) {
02967 case 0:
02968 ctx->data[ctx->data_len++/4]=((uint_least32_t)*(const unsigned char*)data)<<24;
02969 break;
02970 case 1:
02971 ctx->data[ctx->data_len++/4]|=((uint_least32_t)*(const unsigned char*)data)<<16;
02972 break;
02973 case 2:
02974 ctx->data[ctx->data_len++/4]|=((uint_least32_t)*(const unsigned char*)data)<<8;
02975 break;
02976 case 3:
02977 ctx->data[ctx->data_len++/4]|=*(const unsigned char*)data;
02978 break;
02979 }
02980
02981 ctx->cnt+=8;
02982 data=(const unsigned char*)data+1;
02983 len--;
02984 }
02985
02986 assert(ctx->data_len==4*SHA1_LBLOCK);
02987
02988 sha1_transform_chunk(ctx);
02989
02990 ctx->data_len=0;
02991 }
02992
02993 return 1;
02994 }
02995
02999 static void sha1_append_length(struct sha1_ctx *ctx) {
03000 unsigned char lendata[8];
03001
03002 assert(ctx != NULL);
03003
03004
03005 lendata[0]=ctx->cnt>>56;
03006 lendata[1]=ctx->cnt>>48;
03007 lendata[2]=ctx->cnt>>40;
03008 lendata[3]=ctx->cnt>>32;
03009 lendata[4]=ctx->cnt>>24;
03010 lendata[5]=ctx->cnt>>16;
03011 lendata[6]=ctx->cnt>>8;
03012 lendata[7]=ctx->cnt;
03013
03014
03015 sha1_update(ctx, "\x80", 1);
03016 while(ctx->cnt%512 != 448) {
03017 sha1_update(ctx, "", 1);
03018 }
03019
03020
03021 sha1_update(ctx, lendata, sizeof lendata);
03022
03023 assert(ctx->cnt%512 == 0);
03024 }
03025
03029 EXPORT int sha1_final(unsigned char *md, struct sha1_ctx *ctx) {
03030 assert(ctx != NULL);
03031 assert(md != NULL);
03032
03033 sha1_append_length(ctx);
03034
03035 assert(ctx->cnt%512 == 0);
03036
03037
03038 if(md) {
03039 unsigned i;
03040 for(i=0;i<5;i++) {
03041
03042 md[i*4]=ctx->h[i]>>24;
03043 md[i*4+1]=ctx->h[i]>>16;
03044 md[i*4+2]=ctx->h[i]>>8;
03045 md[i*4+3]=ctx->h[i];
03046 }
03047 }
03048
03049 sha1_init(ctx);
03050
03051 return 1;
03052 }
03053
03061 EXPORT unsigned char *sha1(const void *data, size_t len, unsigned char *md) {
03062 struct sha1_ctx ctx;
03063 static unsigned char tmp[SHA1_DIGEST_LENGTH];
03064 sha1_init(&ctx);
03065 sha1_update(&ctx, data, len);
03066 if(!md) md=tmp;
03067 sha1_final(md, &ctx);
03068 return md;
03069 }
03070
03071 #ifndef NTEST
03072 static void sha1_print_digest(const unsigned char *md) {
03073 unsigned i;
03074 for(i=0;i<SHA1_DIGEST_LENGTH;i++) {
03075 printf("%02X", md[i]);
03076 if(i<SHA1_DIGEST_LENGTH-1) printf(":");
03077 }
03078 printf("\n");
03079 }
03080
03081 static int sha1_test(void) {
03082 const char test1[]="The quick brown fox jumps over the lazy dog";
03083 const unsigned char test1_digest[SHA1_DIGEST_LENGTH] = {
03084 0x2f, 0xd4, 0xe1, 0xc6, 0x7a, 0x2d, 0x28, 0xfc, 0xed, 0x84, 0x9e, 0xe1, 0xbb, 0x76, 0xe7, 0x39, 0x1b, 0x93, 0xeb, 0x12,
03085 };
03086 unsigned char digest[SHA1_DIGEST_LENGTH];
03087
03088 memset(digest, 0, sizeof digest);
03089
03090 if(!sha1(test1, strlen(test1), digest)) {
03091 printf("failed.\n");
03092 return 0;
03093 }
03094
03095 printf("calculated : ");
03096 sha1_print_digest(digest);
03097
03098 printf("known : ");
03099 sha1_print_digest(test1_digest);
03100
03101 printf("test1: %s\n", memcmp(digest, test1_digest, SHA1_DIGEST_LENGTH) ? "FAILED" : "PASSED");
03102
03103 return 1;
03104 }
03105 #endif
03106
03107
03108
03109
03111 #define SHA1CRYPT_BITS 128
03112
03114 #define SHA1CRYPT_GENSALT_LEN 6
03115
03117 #define SHA1CRYPT_GENSALT_MAX 16
03118
03120 #define SHA1PASSWD_MAGIC "{SSHA}"
03121
03123 #define SHA1PASSWD_MAGIC_LEN 6
03124
03126 #define SHA1PASSWD_MAX (SHA1PASSWD_MAGIC_LEN+((SHA1_DIGEST_LENGTH+SHA1CRYPT_GENSALT_MAX+3)/4*4)*4/3+1)
03127
03128
03129
03133 static void sha1crypt_gensalt(size_t salt_len, void *salt) {
03134 size_t i;
03135 for(i=0;i<salt_len;i++) {
03136
03137 ((unsigned char*)salt)[i]=(rand()%96)+' ';
03138 }
03139 }
03140
03141 static int sha1crypt_create_password(char *buf, size_t max, const char *plaintext, size_t salt_len, const unsigned char *salt) {
03142 struct sha1_ctx ctx;
03144 unsigned char digest[SHA1_DIGEST_LENGTH+SHA1CRYPT_GENSALT_MAX];
03146 char tmp[((SHA1_DIGEST_LENGTH+SHA1CRYPT_GENSALT_MAX+3)/4*4)*4/3+1];
03147
03148 if(salt_len>SHA1CRYPT_GENSALT_MAX) {
03149 ERROR_MSG("Salt is too large.");
03150 return 0;
03151 }
03152
03153
03154 sha1_init(&ctx);
03155 sha1_update(&ctx, salt, salt_len);
03156 sha1_update(&ctx, plaintext, strlen(plaintext));
03157 sha1_final(digest, &ctx);
03158
03159
03160 memcpy(digest+SHA1_DIGEST_LENGTH, salt, salt_len);
03161
03162
03163 if(base64_encode(SHA1_DIGEST_LENGTH+salt_len, digest, sizeof tmp, tmp)<0) {
03164 ERROR_MSG("Buffer cannot hold password.");
03165 return 0;
03166 }
03167
03169 snprintf(buf, max, "%s%s", SHA1PASSWD_MAGIC, tmp);
03170
03171 TRACE("Password hash: \"%s\"\n", buf);
03172 HEXDUMP_TRACE(salt, salt_len, "Password salt(len=%d): ", salt_len);
03173
03174 return 1;
03175 }
03176
03180 EXPORT int sha1crypt_makepass(char *buf, size_t max, const char *plaintext) {
03181 unsigned char salt[SHA1CRYPT_GENSALT_LEN];
03182
03183 assert(max > 0);
03184
03185
03186 sha1crypt_gensalt(sizeof salt, salt);
03187
03188 return sha1crypt_create_password(buf, max, plaintext, sizeof salt, salt);
03189 }
03190
03191 EXPORT int sha1crypt_checkpass(const char *crypttext, const char *plaintext) {
03192 char tmp[SHA1PASSWD_MAX];
03193 unsigned char digest[SHA1_DIGEST_LENGTH+SHA1CRYPT_GENSALT_MAX];
03194 unsigned char *salt;
03195 int res;
03196 size_t crypttext_len;
03197
03198 crypttext_len=strlen(crypttext);
03199
03200
03201 if(crypttext_len<=SHA1PASSWD_MAGIC_LEN || strncmp(crypttext, SHA1PASSWD_MAGIC, SHA1PASSWD_MAGIC_LEN)) {
03202 ERROR_MSG("not a SHA1 crypt.");
03203 return 0;
03204 }
03205
03206
03207 res=base64_decode(crypttext_len-SHA1PASSWD_MAGIC_LEN, crypttext+SHA1PASSWD_MAGIC_LEN, sizeof digest, digest);
03208 if(res<0 || res<SHA1_DIGEST_LENGTH) {
03209 ERROR_MSG("crypt decode error.");
03210 return 0;
03211 }
03212 salt=&digest[SHA1_DIGEST_LENGTH];
03213
03214
03215 res=sha1crypt_create_password(tmp, sizeof tmp, plaintext, res-SHA1_DIGEST_LENGTH, salt);
03216 if(!res) {
03217 ERROR_MSG("crypt decode error2.");
03218 return 0;
03219 }
03220
03221
03222 return strcmp(tmp, crypttext)==0;
03223 }
03224
03225 #ifndef NTEST
03226
03227
03228 EXPORT void sha1crypt_test(void) {
03229 char buf[SHA1PASSWD_MAX];
03230 int res;
03231 char salt[SHA1CRYPT_GENSALT_LEN];
03232 struct {
03233 char *pass, *hash;
03234 } examples[] = {
03235 { "secret", "{SSHA}2gDsLm/57U00KyShbiYsgvPIsQtzYWx0" },
03236 { "abcdef", "{SSHA}AZz7VpGpy0tnrooaGm++zs9zqgZiVHhbKEc=" },
03237 { "abcdef", "{SSHA}6Nrfz6LziwIo8HsSAkjm/nCeledLUntDZlw=" },
03238 { "abcdeg", "{SSHA}8Lqg317f9lLd0M3EnwIe7BHiH3liVHhbKEc="},
03239 };
03240 unsigned i;
03241
03242
03243 sha1crypt_gensalt(sizeof salt, salt);
03244 HEXDUMP(salt, sizeof salt, "%s(): testing sha1crypt_gensalt() : salt=", __func__);
03245
03246
03247 sha1crypt_makepass(buf, sizeof buf, "abcdef");
03248 printf("buf=\"%s\"\n", buf);
03249 res=sha1crypt_checkpass(buf, "abcdef");
03250 DEBUG("sha1crypt_checkpass() positive:%s (res=%d)\n", !res ? "FAILED" : "PASSED", res);
03251 if(!res) {
03252 ERROR_MSG("sha1crypt_checkpass() must succeed on positive test.");
03253 exit(1);
03254 }
03255
03256
03257 res=sha1crypt_checkpass(buf, "abcdeg");
03258 DEBUG("sha1crypt_checkpass() negative:%s (res=%d)\n", res ? "FAILED" : "PASSED", res);
03259 if(res) {
03260 ERROR_MSG("sha1crypt_checkpass() must fail on negative test.");
03261 exit(1);
03262 }
03263
03264
03265 for(i=0;i<NR(examples);i++) {
03266 res=sha1crypt_checkpass(examples[i].hash, examples[i].pass);
03267 DEBUG("Example %d:%s (res=%d) hash:%s\n", i+1, !res ? "FAILED" : "PASSED", res, examples[i].hash);
03268 }
03269 }
03270 #endif
03271
03272
03273
03274
03278 struct attr_entry *attr_find(struct attr_list *al, const char *name) {
03279 struct attr_entry *curr;
03280 for(curr=LIST_TOP(*al);curr;curr=LIST_NEXT(curr, list)) {
03281
03282 if(!strcmp(curr->name, name)) {
03283 return curr;
03284 }
03285 }
03286 return NULL;
03287 }
03288
03293 int attr_add(struct attr_list *al, const char *name, const char *value) {
03294 struct attr_entry *curr, *prev, *item;
03295
03296 assert(al != NULL);
03297
03298
03299 prev=NULL;
03300 for(curr=LIST_TOP(*al);curr;curr=LIST_NEXT(curr, list)) {
03301
03302 if(!strcmp(curr->name, name)) {
03303 ERROR_FMT("WARNING:attribute '%s' already exists.\n", curr->name);
03304 return 0;
03305 }
03306 prev=curr;
03307 }
03308
03309
03310 item=calloc(1, sizeof *item);
03311 if(!item) {
03312 PERROR("calloc()");
03313 return 0;
03314 }
03315 item->name=strdup(name);
03316 if(!item->name) {
03317 PERROR("strdup()");
03318 free(item);
03319 return 0;
03320 }
03321 item->value=strdup(value);
03322 if(!item->value) {
03323 PERROR("strdup()");
03324 free(item->name);
03325 free(item);
03326 return 0;
03327 }
03328
03329
03330 if(prev) {
03331 assert(curr == NULL);
03332 LIST_INSERT_AFTER(prev, item, list);
03333 } else {
03334 LIST_INSERT_HEAD(al, item, list);
03335 }
03336 return 1;
03337 }
03338
03342 void attr_list_free(struct attr_list *al) {
03343 struct attr_entry *curr;
03344
03345 assert(al != NULL);
03346
03347 while((curr=LIST_TOP(*al))) {
03348 LIST_REMOVE(curr, list);
03349 free(curr->name);
03350 curr->name=NULL;
03351 free(curr->value);
03352 curr->value=NULL;
03353 free(curr);
03354 }
03355 }
03356
03357
03358
03359
03362
03363
03365 #define USER_LEVEL_NEWUSER mud_config.newuser_level
03366
03368 #define USER_FLAGS_NEWUSER mud_config.newuser_flags
03369
03370
03371
03373 struct user {
03374 unsigned id;
03375 char *username;
03376 char *password_crypt;
03377 char *email;
03378 struct acs_info acs;
03379 REFCOUNT_TYPE REFCOUNT_NAME;
03380 struct attr_list extra_values;
03381 };
03382
03383 struct userdb_entry {
03384 struct user *u;
03385 LIST_ENTRY(struct userdb_entry) list;
03386 };
03387
03388
03389
03391 static LIST_HEAD(struct, struct userdb_entry) user_list;
03392
03394 static struct freelist user_id_freelist;
03395
03396
03397
03398 EXPORT int user_exists(const char *username);
03399
03400
03401
03405 static void user_ll_free(struct user *u) {
03406 if(!u) return;
03407 attr_list_free(&u->extra_values);
03408 LIST_INIT(&u->extra_values);
03409 free(u->username);
03410 u->username=0;
03411 free(u->password_crypt);
03412 u->password_crypt=0;
03413 free(u->email);
03414 u->email=0;
03415 free(u);
03416 }
03417
03419 static void user_free(struct user *u) {
03420 if(!u) return;
03421 user_ll_free(u);
03422 }
03423
03427 static struct user *user_defaults(void) {
03428 struct user *u;
03429 u=calloc(1, sizeof *u);
03430 if(!u) {
03431 PERROR("malloc()");
03432 return NULL;
03433 }
03434
03435 u->id=0;
03436 REFCOUNT_INIT(u);
03437 u->username=NULL;
03438 u->password_crypt=NULL;
03439 u->email=NULL;
03440 u->acs.level=USER_LEVEL_NEWUSER;
03441 u->acs.flags=USER_FLAGS_NEWUSER;
03442 LIST_INIT(&u->extra_values);
03443 return u;
03444 }
03445
03449 static int user_ll_add(struct user *u) {
03450 struct userdb_entry *ent;
03451 assert(u != NULL);
03452 assert(u->username != NULL);
03453
03454 if(!u) return 0;
03456 if(user_exists(u->username)) {
03457 return 0;
03458 }
03459
03460 ent=calloc(1, sizeof *ent);
03461 ent->u=u;
03462 LIST_INSERT_HEAD(&user_list, ent, list);
03463 return 1;
03464 }
03465
03467 static struct user *user_load_byname(const char *username) {
03468 struct user *u;
03469 struct fdb_read_handle *h;
03470 const char *name, *value;
03471
03472 h=fdb.read_begin("users", username);
03473 if(!h) {
03474 ERROR_FMT("Could not find user \"%s\"\n", username);
03475 return 0;
03476 }
03477
03478 u=user_defaults();
03479 if(!u) {
03480 ERROR_MSG("Could not allocate user structure");
03481 fdb.read_end(h);
03482 return 0;
03483 }
03484
03485 while(fdb.read_next(h, &name, &value)) {
03486 if(!strcasecmp("id", name))
03487 parse_uint(name, value, &u->id);
03488 else if(!strcasecmp("username", name))
03489 parse_str(name, value, &u->username);
03490 else if(!strcasecmp("pwcrypt", name))
03491 parse_str(name, value, &u->password_crypt);
03492 else if(!strcasecmp("email", name))
03493 parse_str(name, value, &u->email);
03494 else if(!strcasecmp("acs.level", name))
03495 sscanf(value, "%hhu", &u->acs.level);
03496 else if(!strcasecmp("acs.flags", name))
03497 parse_uint(name, value, &u->acs.flags);
03498 else
03499 parse_attr(name, value, &u->extra_values);
03500 }
03501
03502 if(!fdb.read_end(h)) {
03503 ERROR_FMT("Error loading user \"%s\"\n", username);
03504 goto failure;
03505 }
03506
03507 if(u->id<=0) {
03508 ERROR_FMT("User id for user '%s' was not set or set to zero.\n", username);
03509 goto failure;
03510 }
03511
03512 if(!u->username || strcasecmp(username, u->username)) {
03513 ERROR_FMT("User name field for user '%s' was not set or does not math.\n", username);
03514 goto failure;
03515 }
03516
03519 if(!freelist_thwack(&user_id_freelist, u->id, 1)) {
03520 ERROR_FMT("Could not use user id %d (bad id or id already used?)\n", u->id);
03521 goto failure;
03522 }
03523
03524 DEBUG("Loaded user '%s'\n", username);
03525
03526 return u;
03527
03528 failure:
03529 user_ll_free(u);
03530 return 0;
03531 }
03532
03534 static int user_write(const struct user *u) {
03535 struct fdb_write_handle *h;
03536 struct attr_entry *curr;
03537
03538 assert(u != NULL);
03539 assert(u->username != NULL);
03540
03541 h=fdb.write_begin("users", u->username);
03542 if(!h) {
03543 ERROR_FMT("Could not write user \"%s\"\n", u->username);
03544 return 0;
03545 }
03546
03547 fdb.write_format(h, "id", "%u", u->id);
03548 fdb.write_pair(h, "username", u->username);
03549 fdb.write_pair(h, "pwcrypt", u->password_crypt);
03550 fdb.write_pair(h, "email", u->email);
03551 fdb.write_format(h, "acs.level", "%u", u->acs.level);
03552 fdb.write_format(h, "acs.flags", "0x%08x", u->acs.flags);
03553
03554 for(curr=LIST_TOP(u->extra_values);curr;curr=LIST_NEXT(curr, list)) {
03555 fdb.write_pair(h, curr->name, curr->value);
03556 }
03557
03558 if(fdb.write_end(h)) {
03559 ERROR_FMT("Could not write user \"%s\"\n", u->username);
03560 return 0;
03561 }
03562
03563 return 1;
03564 }
03565
03566
03567
03569 EXPORT int user_exists(const char *username) {
03570 struct userdb_entry *curr;
03571
03572 for(curr=LIST_TOP(user_list);curr;curr=LIST_NEXT(curr, list)) {
03573 const struct user *u=curr->u;
03574 assert(u != NULL);
03575 assert(u->username != NULL);
03576
03577 if(!strcasecmp(u->username, username)) {
03578 return 1;
03579 }
03580 }
03581 return 0;
03582 }
03583
03587 EXPORT struct user *user_lookup(const char *username) {
03588 struct userdb_entry *curr;
03589
03590 for(curr=LIST_TOP(user_list);curr;curr=LIST_NEXT(curr, list)) {
03591 struct user *u=curr->u;
03592
03593 assert(u != NULL);
03594 assert(u->username != NULL);
03595
03596
03597
03598
03599
03600
03601
03602
03603
03604
03605 if(!strcasecmp(u->username, username)) {
03606 return u;
03607 }
03608 }
03609
03610 return NULL;
03611 }
03612
03614 EXPORT struct user *user_create(const char *username, const char *password, const char *email) {
03615 struct user *u;
03616 long id;
03617 char password_crypt[SHA1PASSWD_MAX];
03618
03619 if(!username) {
03620 ERROR_MSG("Username was NULL");
03621 return NULL;
03622 }
03623
03624 if(user_exists(username)) {
03625 ERROR_FMT("Username '%s' already exists.\n", username);
03626 return NULL;
03627 }
03628
03629
03630 if(!sha1crypt_makepass(password_crypt, sizeof password_crypt, password)) {
03631 ERROR_MSG("Could not hash password");
03632 return NULL;
03633 }
03634
03635 u=user_defaults();
03636 if(!u) {
03637 DEBUG_MSG("Could not allocate user structure");
03638 return NULL;
03639 }
03640
03641 id=freelist_alloc(&user_id_freelist, 1);
03642 if(id<0) {
03643 ERROR_FMT("Could not allocate user id for username(%s)\n", username);
03644 user_free(u);
03645 return NULL;
03646 }
03647
03648 assert(id>=0);
03649
03650 u->id=id;
03651 u->username=strdup(username);
03652 u->password_crypt=strdup(password_crypt);
03653 u->email=strdup(email);
03654
03655 if(!user_write(u)) {
03656 ERROR_FMT("Could not save account username(%s)\n", u->username);
03657 user_free(u);
03658 return NULL;
03659 }
03660
03661 return u;
03662 }
03663
03665 EXPORT int user_init(void) {
03666 struct fdb_iterator *it;
03667 const char *id;
03668
03669 LIST_INIT(&user_list);
03670
03671 freelist_init(&user_id_freelist);
03672 freelist_pool(&user_id_freelist, 1, 32768);
03673
03674 fdb.domain_init("users");
03675
03676 it=fdb.iterator_begin("users");
03677 if(!it) {
03678 return 0;
03679 }
03680
03681
03682
03683 while((id=fdb.iterator_next(it))) {
03684 struct user *u;
03685
03686 DEBUG("Found user record '%s'\n", id);
03687
03688 u=user_load_byname(id);
03689 if(!u) {
03690 ERROR_FMT("Could not load user from file '%s'\n", id);
03691 goto failure;
03692 }
03694 user_ll_add(u);
03695 }
03696
03697 fdb.iterator_end(it);
03698 return 1;
03699 failure:
03700 fdb.iterator_end(it);
03701 return 0;
03702 }
03703
03705 EXPORT void user_shutdown(void) {
03707 freelist_free(&user_id_freelist);
03708 }
03709
03713 EXPORT void user_put(struct user **user) {
03714 if(user && *user) {
03715 REFCOUNT_PUT(*user, user_free(*user); *user=NULL);
03716 }
03717 }
03718
03722 EXPORT void user_get(struct user *user) {
03723 if(user) {
03724 REFCOUNT_GET(user);
03725 DEBUG("user refcount=%d\n", user->REFCOUNT_NAME);
03726 }
03727 }
03728
03729
03730
03731
03732
03734 struct buffer {
03735 char *data;
03736 size_t used, max;
03737 };
03738
03740 EXPORT void buffer_init(struct buffer *b, size_t max) {
03741 assert(b != NULL);
03742 b->data=malloc(max+1);
03743 b->used=0;
03744 b->max=max;
03745 }
03746
03750 EXPORT void buffer_free(struct buffer *b) {
03751 free(b->data);
03752 b->data=NULL;
03753 b->used=0;
03754 b->max=0;
03755 }
03756
03761 static int buffer_ll_expandnl(struct buffer *b, size_t len) {
03762 size_t rem;
03763 char *p, *e;
03764
03765 assert(b != NULL);
03766
03767 for(p=b->data+b->used,rem=len;(e=memchr(p, '\n', rem));rem-=e-p,p=e+2) {
03768
03769 if(p-b->data>=(ptrdiff_t)b->max) {
03770 DEBUG_MSG("Overflow detected");
03771 return -1;
03772 }
03773 memmove(e+1, e, rem);
03774 *e='\r';
03775 len++;
03776 }
03777
03778 assert(b->used+len <= b->max);
03779 return len;
03780 }
03781
03786 EXPORT int buffer_write_noexpand(struct buffer *b, const void *data, size_t len) {
03787 if(b->used+len>b->max) {
03788 DEBUG_MSG("Overflow detected. refusing to send any data.\n");
03789 return -1;
03790 }
03791
03792 memcpy(&b->data[b->used], data, len);
03793 b->used+=len;
03794
03795 assert(b->used <= b->max);
03796 return len;
03797 }
03798
03802 EXPORT int buffer_write(struct buffer *b, const char *str, size_t len) {
03803 size_t i, j;
03804 int ret;
03805 assert(b != NULL);
03806 if(b->used>=b->max) {
03807 DEBUG("Buffer %p is full\n", (void*)b);
03808 return -1;
03809 }
03810
03811
03812 for(i=0,j=b->used;i<len && j<b->max;i++) {
03813 if(str[i]=='\n') {
03814 b->data[j++]='\r';
03815 }
03816 b->data[j++]=str[i];
03817 }
03818 ret=j-b->used;
03819 b->used=j;
03820 assert(ret>=0);
03821 assert(b->used <= b->max);
03822
03823 if(i<len) {
03824 DEBUG("Truncation detected in buffer %p\n", (void*)b);
03825 return -1;
03826 }
03827 TRACE("Wrote %d bytes to buffer %p\n", j, (void*)b);
03828 return j;
03829 }
03830
03834 static int buffer_puts(struct buffer *b, const char *str) {
03835 return buffer_write(b, str, strlen(str));
03836 }
03837
03841 EXPORT int buffer_vprintf(struct buffer *b, const char *fmt, va_list ap) {
03842 int res;
03843 assert(b != NULL);
03844 if(!b)
03845 return -1;
03846 if(b->used>=b->max) {
03847 DEBUG("Buffer %p is full\n", (void*)b);
03848 return -1;
03849 }
03850
03851 res=vsnprintf(&b->data[b->used], b->max-b->used+1, fmt, ap);
03852 if(res<0) {
03853 res=b->max-b->used+2;
03854 }
03855
03856 if((unsigned)res>b->max-b->used) {
03857
03858 TODO("grow the buffer and try again?");
03859 DEBUG("Truncation detected in buffer %p\n", (void*)b);
03860 res=b->max-b->used;
03861 }
03862 res=buffer_ll_expandnl(b, (unsigned)res);
03863 if(res==-1) {
03864 TODO("test this code");
03865 ERROR_FMT("Overflow in buffer %p\n", (void*)b);
03866 return -1;
03867 }
03868 b->used+=res;
03869 TRACE("Wrote %d bytes to buffer %p\n", res, (void*)b);
03870 return res;
03871 }
03872
03876 static int buffer_printf(struct buffer *b, const char *fmt, ...) {
03877 va_list ap;
03878 int res;
03879 va_start(ap, fmt);
03880 res=buffer_vprintf(b, fmt, ap);
03881 va_end(ap);
03882 return res;
03883 }
03884
03886 EXPORT const char *buffer_data(struct buffer *b, size_t *len) {
03887 assert(b != NULL);
03888 assert(len != NULL);
03889 if(!b) {
03890 *len=0;
03891 return NULL;
03892 }
03893
03894 *len=b->used;
03895 return b->data;
03896 }
03897
03904 EXPORT char *buffer_load(struct buffer *b, size_t *len) {
03905 assert(b != NULL);
03906 assert(len != NULL);
03907 if(!b) {
03908 *len=0;
03909 return NULL;
03910 }
03911
03912 *len=b->max-b->used;
03913 return b->data+b->used;
03914 }
03915
03919 EXPORT unsigned buffer_consume(struct buffer *b, size_t len) {
03920 assert(b != NULL);
03921 DEBUG("len=%zu used=%zu rem=%zu\n", len, b->used, b->max-b->used);
03922 assert(len <= b->used);
03923 if(len>b->used) {
03924 ERROR_FMT("WARNING:attempted ovewflow of output buffer %p\n", (void*)b);
03925 len=b->used;
03926 }
03927 b->used-=len;
03928 assert((signed)b->used >= 0);
03929 memmove(b->data, b->data+len, b->used);
03930 return b->used;
03931 }
03932
03936 EXPORT void buffer_emit(struct buffer *b, size_t len) {
03937 assert(b != NULL);
03938 assert(b->used <= b->max);
03939 assert(b->used + len <= b->max);
03940 b->used+=len;
03941 if(b->used>b->max) {
03942 ERROR_FMT("WARNING:attempted ovewflow of input buffer %p\n", (void*)b);
03943 b->used=b->max;
03944 }
03945 }
03946
03951 static char *buffer_findnl(char *d, size_t *len, size_t (*iac_process)(const char *data, size_t len, void *p), void *p) {
03952 size_t res, tmplen;
03953
03954 assert(d != NULL);
03955 assert(len != NULL);
03956
03957
03958 if(!iac_process) {
03959 return memchr(d, '\n', *len);
03960 }
03961
03962
03963
03964 assert((int)*len>=0);
03965 for(tmplen=*len;tmplen;) {
03966 TRACE("%d: len=%d tmplen=%d\n", __LINE__, *len, tmplen);
03967 assert((int)tmplen>0);
03968 if(*d==IAC) {
03969 assert(iac_process != NULL);
03970 res=iac_process(d, *len, p);
03971 if(!res) {
03972
03973 DEBUG_MSG("Incomplete IAC sequence, wait for more data\n");
03974 return NULL;
03975 }
03976 DEBUG("Telnet control data processed (%zd bytes)\n", res);
03977 TRACE("%d: res=%d len=%d tmplen=%d\n", __LINE__, res, *len, tmplen);
03978 assert((int)res<=(int)*len);
03979 assert((int)tmplen>0);
03980 assert((int)res<=(int)tmplen);
03981 tmplen-=res;
03982 *len-=res;
03983 assert((int)tmplen>=0);
03984 memmove(d, d+res, tmplen);
03985 continue;
03986 }
03987 if(*d=='\n') {
03988 return d;
03989 }
03990 tmplen--;
03991 d++;
03992 assert((int)tmplen>=0);
03993 }
03994
03995 return NULL;
03996 }
03997
03999 EXPORT const char *buffer_getline(struct buffer *b, size_t *consumed_len, size_t (*iac_process)(const char *data, size_t len, void *p), void *p) {
04000 char *d;
04001 assert(b != NULL);
04002 assert(consumed_len != NULL);
04003 d=buffer_findnl(b->data, &b->used, iac_process, p);
04004 if(!d) {
04005
04006 return NULL;
04007 }
04008 if(d>b->data && d[-1]=='\r') {
04009 d[-1]=0;
04010 }
04011 *d=0;
04012 *consumed_len=d-b->data+1;
04013 return b->data;
04014 }
04015
04016
04017
04018
04019 #ifndef USE_WIN32_SOCKETS
04020
04025 typedef int SOCKET;
04026
04028 #define INVALID_SOCKET (-1)
04029
04031 #define SOCKET_ERROR (-1)
04032 #endif
04033
04035 #define SOCKETIO_FAILON(e, reason, fail_label) do { if(e) { fprintf(stderr, "ERROR:%s:%s\n", reason, socketio_strerror()); goto fail_label; } } while(0)
04036
04038 struct socketio_handle {
04039 unsigned type;
04040 LIST_ENTRY(struct socketio_handle) list;
04041 SOCKET fd;
04042 char *name;
04043 unsigned delete_flag:1;
04044 void (*write_event)(struct socketio_handle *sh, SOCKET fd, void *p);
04045 void (*read_event)(struct socketio_handle *sh, SOCKET fd, void *p);
04046 void *extra;
04047 void (*extra_free)(struct socketio_handle *sh, void *extra);
04048 };
04049
04051 static LIST_HEAD(struct socketio_handle_list, struct socketio_handle) socketio_handle_list;
04052
04054 static fd_set *socketio_readfds,
04056 *socketio_writefds;
04057
04059 static unsigned socketio_fdset_sz;
04060
04061 #if defined(USE_WIN32_SOCKETS)
04062
04064 #define socketio_fdmax 0
04065
04067 static unsigned socketio_socket_count;
04068 #else
04069
04071 static SOCKET socketio_fdmax=INVALID_SOCKET;
04072 #endif
04073
04075 static unsigned socketio_delete_count=0;
04076
04077 #if defined(USE_WIN32_SOCKETS) && !defined(gai_strerror)
04078
04080 static const char *gai_strerror(int err) {
04081 switch(err) {
04082 case EAI_AGAIN: return "Temporary failure in name resolution";
04083 case EAI_BADFLAGS: return "Bad value for ai_flags";
04084 case EAI_FAIL: return "Non-recoverable failure in name resolution";
04085 case EAI_FAMILY: return "ai_family not supported";
04086 case EAI_MEMORY: return "Memory allocation failure";
04087 case EAI_NONAME: return "Name or service not known";
04088 case EAI_SERVICE: return "Servname not supported for ai_socktype";
04089 case EAI_SOCKTYPE: return "ai_socktype not supported";
04090 }
04091 return "Unknown resolution error";
04092 }
04093 #endif
04094
04096 EXPORT const char *socketio_strerror(void) {
04097 #if defined(USE_WIN32_SOCKETS)
04098 static char buf[64];
04099 int res;
04100 res=WSAGetLastError();
04101 if(res==0)
04102 return "winsock successful";
04103 snprintf(buf, sizeof buf, "winsock error %d", res);
04104 return buf;
04105 #else
04106 return strerror(errno);
04107 #endif
04108 }
04109
04113 EXPORT int socketio_wouldblock(void) {
04114 #if defined(USE_WIN32_SOCKETS)
04115 return WSAGetLastError()==WSAEWOULDBLOCK;
04116 #else
04117 return errno==EWOULDBLOCK;
04118 #endif
04119 }
04120
04124 EXPORT int socketio_eintr(void) {
04125 #if defined(USE_WIN32_SOCKETS)
04126 return WSAGetLastError()==WSAEINTR;
04127 #else
04128 return errno==EINTR;
04129 #endif
04130 }
04131
04132 #ifndef NTRACE
04133
04134 static void socketio_dump_fdset(fd_set *readfds, fd_set *writefds) {
04135 #if defined(USE_WIN32_SOCKETS)
04136 unsigned i;
04137 fprintf(stderr, "socketio_socket_count=%d\n", socketio_socket_count);
04138 for(i=0;i<readfds->fd_count && i<writefds->fd_count;i++) {
04139 if(i<readfds->fd_count) {
04140 fprintf(stderr, "%s():READ:fd=%u ", __func__, readfds->fd_array[i]);
04141 }
04142 if(i<writefds->fd_count) {
04143 fprintf(stderr, "%s():WRITE:fd=%u", __func__, writefds->fd_array[i]);
04144 }
04145 fprintf(stderr, "\n");
04146 }
04147 #else
04148 SOCKET i;
04149 fprintf(stderr, "socketio_fdmax=%d\n", socketio_fdmax);
04150 for(i=0;i<=socketio_fdmax;i++) {
04151 unsigned r=FD_ISSET(i, readfds), w=FD_ISSET(i, writefds);
04152 if(r||w) {
04153 fprintf(stderr, "%s():fd=%d (%c%c)\n", __func__, i, r?'r':'-', w?'w':'-');
04154 }
04155 }
04156 #endif
04157 }
04158 #endif
04159
04161 EXPORT int socketio_init(void) {
04162 #if defined(USE_WIN32_SOCKETS)
04163 WSADATA wsaData;
04164 int err;
04165
04166 err=WSAStartup(MAKEWORD(2,2), &wsaData);
04167 if(err!=0) {
04168 fprintf(stderr, "WSAStartup() failed (err=%d)\n", err);
04169 return 0;
04170 }
04171 DEBUG("Winsock: VERSION %u.%u\n",
04172 LOBYTE(wsaData.wVersion),
04173 HIBYTE(wsaData.wVersion)
04174 );
04175 #endif
04176
04177 socketio_fdset_sz=FD_SETSIZE;
04178
04179 #if defined(USE_WIN32_SOCKETS)
04180
04181 socketio_readfds=calloc(1, sizeof *socketio_readfds);
04182 socketio_writefds=calloc(1, sizeof *socketio_writefds);
04183 #elif defined(NFDBITS)
04184
04185 socketio_readfds=calloc(1, socketio_fdset_sz/NFDBITS);
04186 socketio_writefds=calloc(1, socketio_fdset_sz/NFDBITS);
04187 #else
04188
04189 #warning Using generic socket code. define _BSD_SOURCE for Unix socket code
04190 socketio_readfds=calloc(1, sizeof *socketio_readfds);
04191 socketio_writefds=calloc(1, sizeof *socketio_writefds);
04192 #endif
04193 return 1;
04194 }
04195
04197 EXPORT void socketio_shutdown(void) {
04198 #if defined(USE_WIN32_SOCKETS)
04199 WSACleanup();
04200 #endif
04201 }
04202
04204 EXPORT int socketio_close(SOCKET *fd) {
04205 int res;
04206 assert(fd!=0);
04207 assert(*fd!=INVALID_SOCKET);
04208 #if defined(USE_WIN32_SOCKETS)
04209 socketio_socket_count--;
04210 res=closesocket(*fd);
04211 #else
04212 res=close(*fd);
04213 #endif
04214 if(res==-1) {
04215 ERROR_FMT("close(fd=%d):%s\n", *fd, socketio_strerror());
04216 }
04217
04218
04219 FD_CLR(*fd, socketio_readfds);
04220 FD_CLR(*fd, socketio_writefds);
04221
04222 *fd=INVALID_SOCKET;
04223 return res;
04224 }
04225
04230 EXPORT int socketio_check_count(SOCKET fd) {
04231 assert(fd!=INVALID_SOCKET);
04232 #if defined(USE_WIN32_SOCKETS)
04233 if(socketio_socket_count>=socketio_fdset_sz) {
04234 DEBUG("too many open sockets (%d) for fd_set (fd_setsize=%d)\n", socketio_socket_count, socketio_fdset_sz);
04235 return 0;
04236 }
04237 #else
04238 if((unsigned)fd>=socketio_fdset_sz) {
04239 DEBUG("too many open sockets (%d) for fd_set (fd_setsize=%d)\n", fd, socketio_fdset_sz);
04240 return 0;
04241 }
04242 if(fd>socketio_fdmax) {
04243 DEBUG("Updating fdmax from %d to %d\n", socketio_fdmax, fd);
04244 socketio_fdmax=fd;
04245 }
04246 #endif
04247 return 1;
04248 }
04249
04253 EXPORT void socketio_readready(SOCKET fd) {
04254 assert(fd!=INVALID_SOCKET);
04255 FD_SET(fd, socketio_readfds);
04256 }
04257
04261 EXPORT void socketio_writeready(SOCKET fd) {
04262 assert(fd!=INVALID_SOCKET);
04263 FD_SET(fd, socketio_writefds);
04264 }
04265
04267 EXPORT int socketio_sockname(struct sockaddr *sa, socklen_t salen, char *name, size_t name_len) {
04268 char servbuf[16];
04269 int res;
04270 size_t tmplen;
04271
04272
04273 if(name_len>=(16+sizeof servbuf)) {
04274 name_len-=sizeof servbuf;
04275 }
04276 res=getnameinfo(sa, salen, name, name_len, servbuf, sizeof servbuf, NI_NUMERICHOST|NI_NUMERICSERV);
04277 SOCKETIO_FAILON(res!=0, "getnameinfo()", failure);
04278
04279 tmplen=strlen(name);
04280 if(name_len>tmplen) {
04281 snprintf(name+tmplen, name_len-tmplen, "/%s", servbuf);
04282 }
04283
04284 return 1;
04285
04286 failure:
04287 return 0;
04288 }
04289
04291 EXPORT int socketio_getpeername(SOCKET fd, char *name, size_t name_len) {
04292 struct sockaddr_storage ss;
04293 socklen_t sslen;
04294 int res;
04295
04296 assert(fd!=INVALID_SOCKET);
04297 assert(name!=NULL);
04298
04299 sslen=sizeof ss;
04300 res=getpeername(fd, (struct sockaddr*)&ss, &sslen);
04301 if(res!=0) {
04302 ERROR_FMT("%s\n", socketio_strerror());
04303 return 0;
04304 }
04305 if(!socketio_sockname((struct sockaddr*)&ss, sslen, name, name_len)) {
04306 ERROR_FMT("Failed on fd %d\n", fd);
04307 return 0;
04308 }
04309 DEBUG("getpeername is %s\n", name);
04310 return 1;
04311 }
04312
04314 static int socketio_nonblock(SOCKET fd) {
04315 int res;
04316 #if defined(USE_WIN32_SOCKETS)
04317 u_long iMode=1;
04318 res=ioctlsocket(fd, (int)FIONBIO, &iMode);
04319 #else
04320 res=fcntl(fd, F_SETFL, O_NONBLOCK);
04321 #endif
04322 SOCKETIO_FAILON(res!=0, "setting non-blocking for accept() socket", failure);
04323 return 1;
04324 failure:
04325 return 0;
04326 }
04327
04329 static void socketio_ll_handle_free(struct socketio_handle *sh) {
04330 assert(sh!=NULL);
04331 if(!sh)
04332 return;
04333 DEBUG("freeing socket handle '%s'\n", sh->name);
04334
04335 if(sh->extra) {
04336 if(sh->extra_free) {
04337 sh->extra_free(sh, sh->extra);
04338 } else {
04339 DEBUG_MSG("WARNING:extra data for socket handle is being leaked");
04340 }
04341 }
04342
04343 if(sh->fd!=INVALID_SOCKET) {
04344 socketio_close(&sh->fd);
04345 }
04346
04347 LIST_REMOVE(sh, list);
04348
04349 free(sh->name);
04350
04351 #ifndef NDEBUG
04352 memset(sh, 0xBB, sizeof *sh);
04353 #endif
04354 free(sh);
04355 }
04356
04358 EXPORT int socketio_send(SOCKET fd, const void *data, size_t len) {
04359 int res;
04360 res=send(fd, data, len, 0);
04361 SOCKETIO_FAILON(res==-1, "send() to socket", failure);
04362 return res;
04363 failure:
04364 return -1;
04365 }
04366
04368 EXPORT int socketio_recv(SOCKET fd, void *data, size_t len) {
04369 int res;
04370 res=recv(fd, data, len, 0);
04371 SOCKETIO_FAILON(res==-1, "recv() from socket", failure);
04372 return res;
04373 failure:
04374 return -1;
04375 }
04376
04378 static void socketio_toomany(SOCKET fd) {
04379 const char buf[]="Too many connections\r\n";
04380
04381 eventlog_toomany();
04382
04383 if(socketio_nonblock(fd)) {
04384 send(fd, buf, (sizeof buf)-1, 0);
04385 socketio_send(fd, buf, (sizeof buf)-1);
04386 }
04387 socketio_close(&fd);
04388 }
04389
04391 static void socketio_fdset_copy(fd_set *dst, const fd_set *src) {
04392 assert(dst!=NULL);
04393 assert(src!=NULL);
04394 #if defined(USE_WIN32_SOCKETS)
04395
04396 dst->fd_count=src->fd_count;
04397 memcpy(dst->fd_array, src->fd_array, src->fd_count * sizeof *src->fd_array);
04398 #elif defined(NFDBITS)
04399
04400 size_t fd_bytes;
04401 assert(socketio_fdmax!=INVALID_SOCKET);
04402 if(socketio_fdmax!=INVALID_SOCKET) {
04403 fd_bytes=ROUNDUP(socketio_fdmax+1, NFDBITS)/8;
04404 } else {
04405 fd_bytes=ROUNDUP(socketio_fdset_sz, NFDBITS)/8;
04406 }
04407 memcpy(dst, src, fd_bytes);
04408 #else
04409
04410 *dst=*src;
04411 #endif
04412
04413 }
04414
04416 static struct socketio_handle *socketio_ll_newhandle(SOCKET fd, const char *name, unsigned type, void (*write_event)(struct socketio_handle *sh, SOCKET fd, void *p), void (*read_event)(struct socketio_handle *sh, SOCKET fd, void *p)) {
04417 struct socketio_handle *ret;
04418
04419 assert(fd != INVALID_SOCKET);
04420
04421 if(!socketio_check_count(fd)) {
04422 ERROR_MSG("too many open sockets. closing new connection!");
04423 socketio_toomany(fd);
04424 return NULL;
04425 }
04426
04427 ret=calloc(1, sizeof *ret);
04428 FAILON(!ret, "malloc()", failure);
04429 ret->type=type;
04430 ret->name=strdup(name);
04431 ret->fd=fd;
04432 ret->delete_flag=0;
04433 ret->read_event=read_event;
04434 ret->write_event=write_event;
04435 LIST_INSERT_HEAD(&socketio_handle_list, ret, list);
04436 socketio_readready(fd);
04437 return ret;
04438 failure:
04439 return NULL;
04440 }
04441
04443 EXPORT int socketio_dispatch(long msec) {
04444 struct socketio_handle *curr, *next;
04445 struct timeval timeout, *to;
04446 int nr;
04447 fd_set out_readfds, out_writefds;
04448
04449 if(msec<0) {
04450
04451 to=NULL;
04452 } else {
04453 timeout.tv_usec=(msec%1000)*1000;
04454 timeout.tv_sec=msec/1000;
04455 assert(timeout.tv_usec < 1000000);
04456 to=&timeout;
04457 }
04458
04459 if(!LIST_TOP(socketio_handle_list)) {
04460 ERROR_MSG("No more sockets to watch");
04461 return 0;
04462 }
04463
04464
04465 for(curr=LIST_TOP(socketio_handle_list);socketio_delete_count && curr;curr=next) {
04466 next=LIST_NEXT(curr, list);
04467 if(curr->delete_flag) {
04468
04469 DEBUG("Deleting %s\n", curr->name);
04470
04471 socketio_close(&curr->fd);
04472 socketio_ll_handle_free(curr);
04473
04474 socketio_delete_count--;
04475 }
04476 }
04477
04478
04479 if(socketio_delete_count!=0) {
04480 ERROR_MSG("WARNING:socketio_delete_count is higher than number of marked sockets");
04481 socketio_delete_count=0;
04482 }
04483
04484 socketio_fdset_copy(&out_readfds, socketio_readfds);
04485 socketio_fdset_copy(&out_writefds, socketio_writefds);
04486
04487 #ifndef NTRACE
04488 socketio_dump_fdset(&out_readfds, &out_writefds);
04489 #endif
04490
04491 if(socketio_fdmax==INVALID_SOCKET) {
04492 DEBUG_MSG("WARNING:currently not waiting on any sockets");
04493 }
04494 nr=select(socketio_fdmax+1, &out_readfds, &out_writefds, 0, to);
04495 if(nr==SOCKET_ERROR) {
04496 SOCKETIO_FAILON(socketio_eintr(), "select()", failure);
04497 return 1;
04498 }
04499
04500 DEBUG("select() returned %d results\n", nr);
04501
04502 TODO("if fds_bits is available then base the loop on the fd_set and look up entries on the client list.");
04503
04504
04505 for(curr=LIST_TOP(socketio_handle_list);nr>0 && curr;curr=next) {
04506 SOCKET fd=curr->fd;
04507
04508 TRACE("Checking socket %s\n", curr->name);
04509
04510 assert(fd!=INVALID_SOCKET);
04511
04512 if(FD_ISSET(fd, &out_writefds)) {
04513
04514 assert(fd!=INVALID_SOCKET);
04515 assert((unsigned)fd < socketio_fdset_sz);
04516 FD_CLR(fd, socketio_writefds);
04517 DEBUG("Write-ready %s\n", curr->name);
04518
04519 if(curr->write_event) {
04520 curr->write_event(curr, fd, curr->extra);
04521 }
04522 nr--;
04523 }
04524
04525 if(FD_ISSET(fd, &out_readfds)) {
04526
04527 assert(fd!=INVALID_SOCKET);
04528 assert((unsigned)fd < socketio_fdset_sz);
04529 FD_CLR(fd, socketio_readfds);
04530 DEBUG("Read-ready %s\n", curr->name);
04531
04532 if(curr->read_event) {
04533 curr->read_event(curr, fd, curr->extra);
04534 }
04535 nr--;
04536 }
04537 next=LIST_NEXT(curr, list);
04538 }
04539 if(nr>0) {
04540 ERROR_FMT("there were %d unhandled socket events\n", nr);
04541 goto failure;
04542 }
04543 assert(nr==0);
04544
04545 return 1;
04546 failure:
04547 return 0;
04548 }
04549
04550
04551
04552
04553
04555 struct server {
04556 void (*newclient)(struct socketio_handle *new_sh);
04557 };
04558
04560 EXPORT void server_read_event(struct socketio_handle *sh, SOCKET fd, void *p) {
04561 struct sockaddr_storage ss;
04562 socklen_t sslen;
04563 struct server *serv=p;
04564 struct socketio_handle *newclient;
04565 char buf[64];
04566 assert(sh!=NULL);
04567 assert(sh->fd!=INVALID_SOCKET);
04568 sslen=sizeof ss;
04569 fd=accept(sh->fd, (struct sockaddr*)&ss, &sslen);
04570 SOCKETIO_FAILON(fd==INVALID_SOCKET, "accept()", failure);
04571
04572 #if defined(USE_WIN32_SOCKETS)
04573 socketio_socket_count++;
04574 #endif
04575
04576 if(!socketio_sockname((struct sockaddr*)&ss, sslen, buf, sizeof buf)) {
04577 strcpy(buf, "<UNKNOWN>");
04578 }
04579
04580 eventlog_connect(buf);
04581
04582 newclient=socketio_ll_newhandle(fd, buf, 1, NULL, NULL);
04583 if(!newclient) {
04584 ERROR_FMT("could not allocate client, closing connection '%s'\n", buf);
04585 socketio_close(&fd);
04586 return;
04587 }
04588 serv->newclient(newclient);
04589 assert(newclient->write_event!=NULL || newclient->read_event!=NULL);
04590
04591 DEBUG("Accepted connection %s\n", newclient->name);
04592 socketio_readready(sh->fd);
04593 return;
04594 failure:
04595 return;
04596 }
04597
04599 static void server_free(struct socketio_handle *sh, void *p) {
04600 struct server *servdata=p;
04601
04602 if(!sh->delete_flag) {
04603 ERROR_MSG("WARNING: delete_flag was not set before freeing");
04604 }
04605
04606
04607 sh->extra=NULL;
04608
04609 #ifndef NDEBUG
04610 memset(servdata, 0xBB, sizeof *servdata);
04611 #endif
04612
04613 free(servdata);
04614 }
04615
04617 static struct socketio_handle *socketio_listen_bind(struct addrinfo *ai, void (*newclient)(struct socketio_handle *new_sh)) {
04618 SOCKET fd;
04619 int res;
04620 char buf[64];
04621 struct socketio_handle *newserv;
04622 struct server *servdata;
04623 struct linger li;
04624
04625 const int yes=1;
04626 assert(ai!=NULL);
04627 if(!ai || !ai->ai_addr) {
04628 ERROR_MSG("empty socket address");
04629 return 0;
04630 }
04631 fd=socket(ai->ai_family, ai->ai_socktype, 0);
04632 SOCKETIO_FAILON(fd==INVALID_SOCKET, "creating socket", failure_clean);
04633
04634 #if defined(USE_WIN32_SOCKETS)
04635 socketio_socket_count++;
04636 #endif
04637 if(!socketio_check_count(fd)) {
04638 ERROR_MSG("too many open sockets. refusing new server!");
04639 goto failure;
04640 }
04641
04642 if(ai->ai_family==AF_INET || ai->ai_family==AF_INET6) {
04643 SOCKETIO_FAILON(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void*)&yes, sizeof yes)!=0, "setting SO_REUSEADDR", failure);
04644 li.l_onoff=0;
04645 li.l_linger=10;
04646 SOCKETIO_FAILON(setsockopt(fd, SOL_SOCKET, SO_LINGER, (const void*)&li, sizeof li)!=0, "setting SO_LINGER", failure);
04647 }
04648
04649 SOCKETIO_FAILON(bind(fd, ai->ai_addr, (socklen_t)ai->ai_addrlen)!=0, "binding to port", failure);
04650
04651 if(!socketio_nonblock(fd)) {
04652 goto failure;
04653 }
04654
04655 res=listen(fd, SOCKETIO_LISTEN_QUEUE);
04656 SOCKETIO_FAILON(res!=0, "forming listening socket", failure);
04657
04658 if(!socketio_sockname(ai->ai_addr, (socklen_t)ai->ai_addrlen, buf, sizeof buf)) {
04659 strcpy(buf, "<UNKNOWN>");
04660 }
04661
04662
04663 newserv=socketio_ll_newhandle(fd, buf, 0, NULL, server_read_event);
04664 if(!newserv) {
04665 ERROR_FMT("could not allocate server, closing socket '%s'\n", buf);
04666 socketio_close(&fd);
04667 return 0;
04668 }
04669
04670 servdata=calloc(1, sizeof *servdata);
04671 servdata->newclient=newclient;
04672
04673 newserv->extra=servdata;
04674 newserv->extra_free=server_free;
04675
04676 DEBUG("Bind success: %s %s\n", ai->ai_family==AF_INET ? "IPv4" : ai->ai_family==AF_INET6 ? "IPv6" : "Unknown", buf);
04677
04678 return newserv;
04679
04680 failure:
04681 socketio_close(&fd);
04682 failure_clean:
04683 return 0;
04684 }
04685
04695 EXPORT struct socketio_handle *socketio_listen(int family, int socktype, const char *host, const char *port, void (*newclient)(struct socketio_handle *sh)) {
04696 int res;
04697 struct addrinfo *ai_res, *curr;
04698 struct addrinfo ai_hints;
04699 struct socketio_handle *ret;
04700
04701 assert(port!=NULL);
04702 assert(family==0 || family==AF_INET || family==AF_INET6);
04703 assert(socktype==SOCK_STREAM || socktype==SOCK_DGRAM);
04704
04705 memset(&ai_hints, 0, sizeof ai_hints);
04706 ai_hints.ai_flags=AI_PASSIVE;
04707 ai_hints.ai_family=family;
04708 ai_hints.ai_socktype=socktype;
04709
04710 res=getaddrinfo(host, port, &ai_hints, &ai_res);
04711
04712 if(res!=0) {
04713 ERROR_FMT("hostname parsing error:%s\n", gai_strerror(res));
04714 return 0;
04715 }
04716
04717
04718 for(curr=ai_res;curr;curr=curr->ai_next) {
04719 TRACE("getaddrinfo():family=%d type=%d\n", curr->ai_family, curr->ai_socktype);
04720 if(curr->ai_family==AF_INET6 || curr->ai_family==AF_INET) {
04721 break;
04722 }
04723 }
04724
04725 if(!curr) {
04726 freeaddrinfo(ai_res);
04727 ERROR_FMT("Could not find interface for %s:%s\n", host ? host : "*", port);
04728 return 0;
04729 }
04730
04731 assert(socktype==SOCK_STREAM || socktype==SOCK_DGRAM);
04732
04733 ret=socketio_listen_bind(curr, newclient);
04734 if(!ret) {
04735 freeaddrinfo(ai_res);
04736 ERROR_FMT("Could bind socket for %s:%s\n", host ? host : "*", port);
04737 return 0;
04738 }
04739
04740 freeaddrinfo(ai_res);
04741 return ret;
04742 }
04743
04744
04745
04746
04747
04749 struct telnetclient {
04750 struct socketio_handle *sh;
04751 struct buffer output, input;
04753 struct terminal {
04754 int width, height;
04755 char name[32];
04756 } terminal;
04757 int prompt_flag;
04758 const char *prompt_string;
04759 void (*line_input)(struct telnetclient *cl, const char *line);
04760 void (*state_free)(struct telnetclient *cl);
04762 union state_data {
04764 struct login_state {
04765 char username[16];
04766 } login;
04767 struct form_state form;
04769 struct menu_state {
04770 const struct menuinfo *menu;
04771 } menu;
04772 } state;
04773 struct user *user;
04774 unsigned nr_channel;
04775 struct channel **channel;
04776 struct channel_member channel_member;
04777 };
04778
04782 EXPORT const char *telnetclient_username(struct telnetclient *cl) {
04783 return cl && cl->user && cl->user->username ? cl->user->username : "<UNKNOWN>";
04784 }
04785
04787 EXPORT int telnetclient_puts(struct telnetclient *cl, const char *str) {
04788 int res;
04789 assert(cl != NULL);
04790 assert(cl->sh != NULL);
04791 res=buffer_puts(&cl->output, str);
04792 socketio_writeready(cl->sh->fd);
04793 cl->prompt_flag=0;
04794 return res;
04795 }
04796
04798 EXPORT int telnetclient_vprintf(struct telnetclient *cl, const char *fmt, va_list ap) {
04799 int res;
04800
04801 assert(cl != NULL);
04802 assert(cl->sh != NULL);
04803 assert(fmt != NULL);
04804
04805 res=buffer_vprintf(&cl->output, fmt, ap);
04806 socketio_writeready(cl->sh->fd);
04807 cl->prompt_flag=0;
04808 return res;
04809 }
04810
04812 EXPORT int telnetclient_printf(struct telnetclient *cl, const char *fmt, ...) {
04813 va_list ap;
04814 int res;
04815
04816 assert(cl != NULL);
04817 assert(cl->sh != NULL);
04818 assert(fmt != NULL);
04819
04820 va_start(ap, fmt);
04821 res=buffer_vprintf(&cl->output, fmt, ap);
04822 va_end(ap);
04823 socketio_writeready(cl->sh->fd);
04824 cl->prompt_flag=0;
04825 return res;
04826 }
04827
04829 static void telnetclient_clear_statedata(struct telnetclient *cl) {
04830 if(cl->state_free) {
04831 cl->state_free(cl);
04832 cl->state_free=NULL;
04833 }
04834 memset(&cl->state, 0, sizeof cl->state);
04835 }
04836
04837 static int telnetclient_channel_add(struct telnetclient *cl, struct channel *ch) {
04838 struct channel **newlist;
04839
04840 assert(cl != NULL);
04841
04842 if(!ch) return 1;
04843 if(!channel.join(ch, &cl->channel_member)) return 0;
04844
04845 newlist=realloc(cl->channel, sizeof *cl->channel * (cl->nr_channel+1));
04846 if(!newlist) {
04847 PERROR("realloc()");
04848 return 0;
04849 }
04850
04851 cl->channel=newlist;
04852 cl->channel[cl->nr_channel++]=ch;
04853 return 1;
04854 }
04855
04856 static int telnetclient_channel_remove(struct telnetclient *cl, struct channel *ch) {
04857 unsigned i;
04858
04859 assert(cl != NULL);
04860
04861 if(!ch) return 1;
04862
04863 for(i=0;i<cl->nr_channel;i++) {
04864 if(cl->channel[i]==ch) {
04865 DEBUG("channel.part(%p, %p)\n", cl->channel[i], &cl->channel_member);
04866
04867 channel.part(cl->channel[i], &cl->channel_member);
04868
04869 cl->channel[i]=NULL;
04870 assert(cl->nr_channel > 0);
04871 cl->channel[i]=cl->channel[--cl->nr_channel];
04872
04873 if(!cl->nr_channel) {
04874
04875 free(cl->channel);
04876 cl->channel=NULL;
04877 }
04878 return 1;
04879 }
04880 }
04881 return 0;
04882 }
04883
04885 static void telnetclient_free(struct socketio_handle *sh, void *p) {
04886 struct telnetclient *client=p;
04887
04888 assert(client!=NULL);
04889 if(!client)
04890 return;
04891
04892 TODO("Determine if connection was logged in first");
04893 eventlog_signoff(telnetclient_username(client), sh->name);
04895 DEBUG("freeing client '%s'\n", sh->name);
04896
04897 if(sh->fd!=INVALID_SOCKET) {
04898 TODO("I forget the purpose of this code");
04899
04900 socketio_readready(sh->fd);
04901 }
04902
04903 if(!sh->delete_flag) {
04904 ERROR_MSG("WARNING: delete_flag was not set before freeing");
04905 }
04906
04907
04908
04909 client->channel_member.send=NULL;
04910 client->channel_member.p=NULL;
04911 DEBUG("client->nr_channel=%d\n", client->nr_channel);
04912 while(client->nr_channel) {
04913 telnetclient_channel_remove(client, client->channel[0]);
04914 }
04915
04916 telnetclient_clear_statedata(client);
04917
04918
04919 sh->extra=NULL;
04920 client->sh=NULL;
04921
04922 buffer_free(&client->output);
04923 buffer_free(&client->input);
04924
04925 user_put(&client->user);
04926
04927 TODO("free any other data structures associated with client");
04928
04929 #ifndef NDEBUG
04930 memset(client, 0xBB, sizeof *client);
04931 #endif
04932
04933 free(client);
04934 }
04935
04936 static void telnetclient_channel_send(struct channel_member *cm, struct channel *ch, const char *msg) {
04937 struct telnetclient *cl;
04938
04939 assert(cm != NULL);
04940 assert(msg != NULL);
04941
04942 if(!cm) return;
04943 cl=cm->p;
04944
04945
04946 telnetclient_printf(cl, "[%p] %s\n", (void*)ch, msg);
04947 }
04948
04950 static struct telnetclient *telnetclient_newclient(struct socketio_handle *sh) {
04951 struct telnetclient *cl;
04952 cl=malloc(sizeof *cl);
04953 FAILON(!cl, "malloc()", failed);
04954
04955 JUNKINIT(cl, sizeof *cl);
04956
04957 buffer_init(&cl->output, TELNETCLIENT_OUTPUT_BUFFER_SZ);
04958 buffer_init(&cl->input, TELNETCLIENT_INPUT_BUFFER_SZ);
04959 cl->terminal.width=cl->terminal.height=0;
04960 strcpy(cl->terminal.name, "");
04961 cl->state_free=NULL;
04962 telnetclient_clear_statedata(cl);
04963 cl->line_input=NULL;
04964 cl->prompt_flag=0;
04965 cl->prompt_string=NULL;
04966 cl->sh=sh;
04967 cl->user=NULL;
04968
04969 cl->nr_channel=0;
04970 cl->channel=NULL;
04971 cl->channel_member.send=telnetclient_channel_send;
04972 cl->channel_member.p=cl;
04973
04974 sh->extra=cl;
04975 sh->extra_free=telnetclient_free;
04976
04977 telnetclient_channel_add(cl, channel.public(0));
04978
04979 return cl;
04980 failed:
04981 return NULL;
04982 }
04983
04987 static void telnetclient_setuser(struct telnetclient *cl, struct user *u) {
04988 struct user *old_user;
04989 assert(cl != NULL);
04990 old_user=cl->user;
04991 cl->user=u;
04992 user_get(u);
04993 user_put(&old_user);
04994 }
04995
04999 static int telnetclient_telnet_init(struct telnetclient *cl) {
05000 const char support[] = {
05001 IAC, DO, TELOPT_LINEMODE,
05002 IAC, DO, TELOPT_NAWS,
05003 IAC, DO, TELOPT_TTYPE,
05004 IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE,
05005 };
05006 if(buffer_write_noexpand(&cl->output, support, sizeof support)<0) {
05007 DEBUG_MSG("write failure");
05008 telnetclient_close(cl);
05009 return 0;
05010 }
05011
05012 return 1;
05013 }
05014
05016 static int telnetclient_echomode(struct telnetclient *cl, int mode) {
05017 static const char echo_off[] = { IAC, WILL, TELOPT_ECHO };
05018 static const char echo_on[] = { IAC, WONT, TELOPT_ECHO };
05019 const char *s;
05020 size_t len;
05021 if(mode) {
05022 s=echo_on;
05023 len=sizeof echo_on;
05024 } else {
05025 s=echo_off;
05026 len=sizeof echo_off;
05027 }
05028
05029 if(buffer_write_noexpand(&cl->output, s, len)<0) {
05030 DEBUG_MSG("write failure");
05031 cl->sh->delete_flag=1;
05032 return 0;
05033 }
05034 return 1;
05035 }
05036
05038 static int telnetclient_linemode(struct telnetclient *cl, int mode) {
05039 const char enable[] = {
05040 IAC, SB, TELOPT_LINEMODE, LM_MODE, MODE_EDIT|MODE_TRAPSIG, IAC, SE
05041 };
05042 const char disable[] = {
05043 IAC, SB, TELOPT_LINEMODE, LM_MODE, MODE_TRAPSIG, IAC, SE
05044 };
05045 const char *s;
05046 size_t len;
05047
05048 if(mode) {
05049 s=enable;
05050 len=sizeof enable;
05051 } else {
05052 s=disable;
05053 len=sizeof disable;
05054 }
05055
05056 if(buffer_write_noexpand(&cl->output, s, len)<0) {
05057 DEBUG_MSG("write failure");
05058 cl->sh->delete_flag=1;
05059 return 0;
05060 }
05061 return 1;
05062 }
05063
05065 EXPORT void telnetclient_write_event(struct socketio_handle *sh, SOCKET fd, void *p) {
05066 const char *data;
05067 size_t len;
05068 int res;
05069 struct telnetclient *cl=p;
05070
05071 assert(cl->sh->delete_flag == 0);
05072
05073
05074 assert(cl != NULL);
05075 assert(sh == cl->sh);
05076
05077 data=buffer_data(&cl->output, &len);
05078 res=socketio_send(fd, data, len);
05079 if(res<0) {
05080 sh->delete_flag=1;
05081 return;
05082 }
05083 TRACE("len=%zu res=%zu\n", len, res);
05084 len=buffer_consume(&cl->output, (unsigned)res);
05085
05086 if(len>0) {
05087
05088 socketio_writeready(fd);
05089 }
05090 }
05091
05095 static void telnetclient_iac_process_sb(const char *iac, size_t len, struct telnetclient *cl) {
05096 assert(cl != NULL);
05097 assert(iac[0] == IAC);
05098 assert(iac[1] == SB);
05099 if(!iac) return;
05100 if(!cl) return;
05101
05102 switch(iac[2]) {
05103 case TELOPT_TTYPE:
05104 if(iac[3]==TELQUAL_IS) {
05105 if(len<9) {
05106 ERROR_MSG("WARNING: short IAC SB TTYPE IS .. IAC SE");
05107 return;
05108 }
05109 snprintf(cl->terminal.name, sizeof cl->terminal.name, "%.*s", (int)len-4-2, iac+4);
05110 DEBUG("%s:Client terminal type is now \"%s\"\n", cl->sh->name, cl->terminal.name);
05111
05112
05113
05114 }
05115 break;
05116 case TELOPT_NAWS: {
05117 if(len<9) {
05118 ERROR_MSG("WARNING: short IAC SB NAWS .. IAC SE");
05119 return;
05120 }
05121 assert(len==9);
05122 cl->terminal.width=RD_BE16(iac, 3);
05123 cl->terminal.height=RD_BE16(iac, 5);
05124 DEBUG("%s:Client display size is now %ux%u\n", cl->sh->name, cl->terminal.width, cl->terminal.height);
05125
05126
05127
05128 break;
05129 }
05130 }
05131 }
05132
05136 static size_t telnetclient_iac_process(const char *iac, size_t len, void *p) {
05137 struct telnetclient *cl=p;
05138 const char *endptr;
05139
05140 assert(iac != NULL);
05141 assert(iac[0] == IAC);
05142
05143 if(iac[0]!=IAC) {
05144 ERROR_MSG("called on non-telnet data\n");
05145 return 0;
05146 }
05147
05148 switch(iac[1]) {
05149 case IAC:
05150 return 1;
05151 case WILL:
05152 if(len>=3) {
05153 DEBUG("IAC WILL %hhu\n", iac[2]);
05154 return 3;
05155 } else {
05156 return 0;
05157 }
05158 case WONT:
05159 if(len>=3) {
05160 DEBUG("IAC WONT %hhu\n", iac[2]);
05161 return 3;
05162 } else {
05163 return 0;
05164 }
05165 case DO:
05166 if(len>=3) {
05167 DEBUG("IAC DO %hhu\n", iac[2]);
05168 return 3;
05169 } else {
05170 return 0;
05171 }
05172 case DONT:
05173 if(len>=3) {
05174 DEBUG("IAC DONT %hhu\n", iac[2]);
05175 return 3;
05176 } else {
05177 return 0;
05178 }
05179 case SB:
05180
05181 TRACE("IAC SB %hhu found\n", iac[2]);
05182 endptr=iac+2;
05183 while((endptr=memchr(endptr, IAC, len-(endptr-iac)))) {
05184 assert(endptr[0] == IAC);
05185 TRACE("found IAC %hhu\n", endptr[1]);
05186 endptr++;
05187 if((endptr-iac)>=(ptrdiff_t)len) {
05188 DEBUG_MSG("Unterminated IAC SB sequence");
05189 return 0;
05190 }
05191 if(endptr[0]==SE) {
05192 endptr++;
05193
05194 HEXDUMP(iac, endptr-iac, "%s():IAC SB %hhu: ", __func__, iac[2]);
05195 telnetclient_iac_process_sb(iac, (size_t)(endptr-iac), cl);
05196 return endptr-iac;
05197 } else if(endptr[0]==IAC) {
05198 TRACE_MSG("Found IAC IAC in IAC SB block");
05199 endptr++;
05200 }
05201 }
05202 return 0;
05203 case SE:
05204 ERROR_MSG("found IAC SE without IAC SB, ignoring it.");
05205 default:
05206 if(len>=3)
05207 return 2;
05208 else
05209 return 0;
05210 }
05211
05212
05213
05214 }
05215
05219 static int telnetclient_recv(struct socketio_handle *sh, struct telnetclient *cl) {
05220 char *data;
05221 size_t len;
05222 int res;
05223
05224 data=buffer_load(&cl->input, &len);
05225 if(len==0) {
05226 ERROR_FMT("WARNING:input buffer full, closing connection %s\n", sh->name);
05227 goto failure;
05228 }
05229 res=socketio_recv(sh->fd, data, len);
05230 if(res<=0) {
05231
05232 goto failure;
05233 }
05234 DEBUG("res=%u\n", res);
05235 buffer_emit(&cl->input, (unsigned)res);
05236
05237 DEBUG("Client %d(%s):received %d bytes (used=%zu)\n", sh->fd, sh->name, res, cl->input.used);
05238 return 1;
05239 failure:
05240
05241 telnetclient_close(cl);
05242 return 0;
05243 }
05244
05246 EXPORT void telnetclient_rdev_lineinput(struct socketio_handle *sh, SOCKET fd, void *extra) {
05247 const char *line;
05248 size_t consumed;
05249 struct telnetclient *cl=extra;
05250
05251
05252 if(!telnetclient_recv(sh, cl)) {
05253 return;
05254 }
05255
05256
05257 while((line=buffer_getline(&cl->input, &consumed, telnetclient_iac_process, cl))) {
05258 DEBUG("client line: '%s'\n", line);
05259
05260 if(cl->line_input) {
05261 cl->line_input(cl, line);
05262 }
05263
05264 buffer_consume(&cl->input, consumed);
05265
05266 if(sh->read_event!=telnetclient_rdev_lineinput) break;
05267 }
05268 socketio_readready(fd);
05269 return;
05270 }
05271
05273 static void telnetclient_setprompt(struct telnetclient *cl, const char *prompt) {
05274 cl->prompt_string=prompt?prompt:"? ";
05275 telnetclient_puts(cl, cl->prompt_string);
05276 cl->prompt_flag=1;
05277 }
05278
05280 static void telnetclient_start_lineinput(struct telnetclient *cl, void (*line_input)(struct telnetclient *cl, const char *line), const char *prompt) {
05281 assert(cl != NULL);
05282 telnetclient_setprompt(cl, prompt);
05283 cl->line_input=line_input;
05284 cl->sh->read_event=telnetclient_rdev_lineinput;
05285 }
05286
05290 static int telnetclient_isstate(struct telnetclient *cl, void (*line_input)(struct telnetclient *cl, const char *line), const char *prompt) {
05291
05292 if(!cl) return 0;
05293
05294 return cl->sh->read_event==telnetclient_rdev_lineinput && cl->line_input==line_input && cl->prompt_string==prompt;
05295 }
05296
05298 static void menu_lineinput(struct telnetclient *cl, const char *line) {
05299 menu_input(cl, cl->state.menu.menu, line);
05300 }
05301
05303 static void telnetclient_start_menuinput(struct telnetclient *cl, struct menuinfo *menu) {
05304 telnetclient_clear_statedata(cl);
05305 cl->state.menu.menu=menu;
05306 menu_show(cl, cl->state.menu.menu);
05307 telnetclient_start_lineinput(cl, menu_lineinput, mud_config.menu_prompt);
05308 }
05309
05311 EXPORT void telnetclient_new_event(struct socketio_handle *sh) {
05312 struct telnetclient *cl;
05313
05314 cl=telnetclient_newclient(sh);
05315 if(!cl) {
05316 return;
05317 }
05318
05319 sh->write_event=telnetclient_write_event;
05320 sh->read_event=NULL;
05321
05322 if(!telnetclient_telnet_init(cl) || !telnetclient_linemode(cl, 1) || !telnetclient_echomode(cl, 1)) {
05323 return;
05324 }
05325
05326 fprintf(stderr, "*** Connection %d: %s\n", sh->fd, sh->name);
05327 telnetclient_puts(cl, mud_config.msgfile_welcome);
05328 telnetclient_start_menuinput(cl, &gamemenu_login);
05329 }
05330
05332 EXPORT void telnetclient_close(struct telnetclient *cl) {
05333 if(cl && cl->sh && !cl->sh->delete_flag) {
05334 cl->sh->delete_flag=1;
05335 socketio_delete_count++;
05336 }
05337 }
05338
05340 EXPORT void telnetclient_prompt_refresh(struct telnetclient *cl) {
05341 if(cl && cl->prompt_string && !cl->prompt_flag) {
05342 telnetclient_setprompt(cl, cl->prompt_string);
05343 }
05344 }
05345
05347 EXPORT void telnetclient_prompt_refresh_all(void) {
05348 struct socketio_handle *curr, *next;
05349 for(curr=LIST_TOP(socketio_handle_list);curr;curr=next) {
05350 next=LIST_NEXT(curr, list);
05351 if(curr->type==1 && curr->extra) {
05352 telnetclient_prompt_refresh(curr->extra);
05353 }
05354 }
05355 }
05356
05357
05358
05359
05360
05362 struct menuitem {
05363 LIST_ENTRY(struct menuitem) item;
05364 char *name;
05365 char key;
05366 void (*action_func)(void *p, long extra2, void *extra3);
05367 long extra2;
05368 void *extra3;
05369 };
05370
05372 EXPORT void menu_create(struct menuinfo *mi, const char *title) {
05373 assert(mi!=NULL);
05374 LIST_INIT(&mi->items);
05375 mi->title_width=strlen(title);
05376 mi->title=malloc(mi->title_width+1);
05377 FAILON(!mi->title, "malloc()", failed);
05378 strcpy(mi->title, title);
05379 mi->tail=NULL;
05380 failed:
05381 return;
05382 }
05383
05385 EXPORT void menu_additem(struct menuinfo *mi, int ch, const char *name, void (*func)(void*, long, void*), long extra2, void *extra3) {
05386 struct menuitem *newitem;
05387 newitem=malloc(sizeof *newitem);
05388 newitem->name=strdup(name);
05389 newitem->key=ch;
05390 TODO("check for duplicate keys");
05391 newitem->action_func=func;
05392 newitem->extra2=extra2;
05393 newitem->extra3=extra3;
05394 if(mi->tail) {
05395 LIST_INSERT_AFTER(mi->tail, newitem, item);
05396 } else {
05397 LIST_INSERT_HEAD(&mi->items, newitem, item);
05398 }
05399 mi->tail=newitem;
05400 }
05401
05405 static void menu_titledraw(struct telnetclient *cl, const char *title, size_t len) {
05406 #if __STDC_VERSION__ >= 199901L
05407 char buf[len+2];
05408 #else
05409 char buf[256];
05410 if(len>sizeof buf-1)
05411 len=sizeof buf-1;
05412 #endif
05413 memset(buf, '=', len);
05414 buf[len]='\n';
05415 buf[len+1]=0;
05416 if(cl)
05417 telnetclient_puts(cl, buf);
05418 DEBUG("%s>>%s", cl?cl->sh->name:"", buf);
05419 if(cl)
05420 telnetclient_printf(cl, "%s\n", title);
05421 DEBUG("%s>>%s\n", cl?cl->sh->name:"", title);
05422 if(cl)
05423 telnetclient_puts(cl, buf);
05424 DEBUG("%s>>%s", cl?cl->sh->name:"", buf);
05425 }
05426
05428 EXPORT void menu_show(struct telnetclient *cl, const struct menuinfo *mi) {
05429 const struct menuitem *curr;
05430
05431 assert(mi != NULL);
05432 menu_titledraw(cl, mi->title, mi->title_width);
05433 for(curr=LIST_TOP(mi->items);curr;curr=LIST_NEXT(curr, item)) {
05434 if(curr->key) {
05435 if(cl)
05436 telnetclient_printf(cl, "%c. %s\n", curr->key, curr->name);
05437 DEBUG("%s>>%c. %s\n", cl?cl->sh->name:"", curr->key, curr->name);
05438 } else {
05439 if(cl)
05440 telnetclient_printf(cl, "%s\n", curr->name);
05441 DEBUG("%s>>%s\n", cl?cl->sh->name:"", curr->name);
05442 }
05443 }
05444 }
05445
05447 EXPORT void menu_input(struct telnetclient *cl, const struct menuinfo *mi, const char *line) {
05448 const struct menuitem *curr;
05449 while(*line && isspace(*line)) line++;
05450 for(curr=LIST_TOP(mi->items);curr;curr=LIST_NEXT(curr, item)) {
05451 if(tolower(*line)==tolower(curr->key)) {
05452 if(curr->action_func) {
05453 curr->action_func(cl, curr->extra2, curr->extra3);
05454 } else {
05455 telnetclient_puts(cl, mud_config.msg_unsupported);
05456 menu_show(cl, mi);
05457 }
05458 return;
05459 }
05460 }
05461 telnetclient_puts(cl, mud_config.msg_invalidselection);
05462 menu_show(cl, mi);
05463 telnetclient_setprompt(cl, mud_config.menu_prompt);
05464 }
05465
05469 static void menu_start(void *p, long unused2 UNUSED, void *extra3) {
05470 struct telnetclient *cl=p;
05471 struct menuinfo *mi=extra3;
05472 telnetclient_start_menuinput(cl, mi);
05473 }
05474
05475
05476
05477
05478
05480 static int command_do_pose(struct telnetclient *cl, struct user *u, const char *cmd UNUSED, const char *arg) {
05481 TODO("Get user name");
05482 TODO("Broadcast to everyone in current room");
05483 telnetclient_printf(cl, "%s %s\n", telnetclient_username(cl), arg);
05484 return 1;
05485 }
05486
05488 static int command_do_yell(struct telnetclient *cl, struct user *u, const char *cmd UNUSED, const char *arg) {
05489 TODO("Get user name");
05490 TODO("Broadcast to everyone in yelling distance");
05491 telnetclient_printf(cl, "%s yells \"%s\"\n", telnetclient_username(cl), arg);
05492 return 1;
05493 }
05494
05496 static int command_do_say(struct telnetclient *cl, struct user *u, const char *cmd UNUSED, const char *arg) {
05497 struct channel *ch;
05498 struct channel_member *exclude_list[1];
05499 TODO("Get user name");
05500 telnetclient_printf(cl, "You say \"%s\"\n", arg);
05501 ch=channel.public(0);
05502 exclude_list[0]=&cl->channel_member;
05503 channel.broadcast(ch, exclude_list, 1, "%s says \"%s\"\n", telnetclient_username(cl), arg);
05504 return 1;
05505 }
05506
05508 static int command_do_emote(struct telnetclient *cl, struct user *u, const char *cmd UNUSED, const char *arg) {
05509 TODO("Get user name");
05510 TODO("Broadcast to everyone in current room");
05511 telnetclient_printf(cl, "%s %s\n", telnetclient_username(cl), arg);
05512 return 1;
05513 }
05514
05516 static int command_do_chsay(struct telnetclient *cl, struct user *u, const char *cmd UNUSED, const char *arg) {
05517 TODO("pass the channel name in a way that makes sense");
05518 TODO("Get user name");
05519 TODO("Broadcast to everyone in a channel");
05520 telnetclient_printf(cl, "%s says \"%s\"\n", telnetclient_username(cl), arg);
05521 return 1;
05522 }
05523
05525 static int command_do_quit(struct telnetclient *cl, struct user *u UNUSED, const char *cmd UNUSED, const char *arg UNUSED) {
05530 telnetclient_close(cl);
05531 return 1;
05532 }
05533
05535 static int command_do_roomget(struct telnetclient *cl, struct user *u, const char *cmd UNUSED, const char *arg) {
05536 struct room *r;
05537 char roomnum_str[64];
05538 unsigned roomnum;
05539 char attrname[64];
05540 const char *attrvalue;
05541
05542 arg=util_getword(arg, roomnum_str, sizeof roomnum_str);
05543 roomnum=strtoul(roomnum_str, 0, 10);
05544
05545 arg=util_getword(arg, attrname, sizeof attrname);
05546
05547 r=room.get(roomnum);
05548 if(!r) {
05549 telnetclient_printf(cl, "room \"%s\" not found.\n", roomnum_str);
05550 return 0;
05551 }
05552 attrvalue=room.attr_get(r, attrname);
05553 if(attrvalue) {
05554 telnetclient_printf(cl, "room \"%s\" \"%s\" = \"%s\"\n", roomnum_str, attrname, attrvalue);
05555 } else {
05556 telnetclient_printf(cl, "room \"%s\" attribute \"%s\" not found.\n", roomnum_str, attrname);
05557 }
05558 room.put(r);
05559
05560 return 1;
05561 }
05562
05563 static int command_do_character(struct telnetclient *cl, struct user *u, const char *cmd UNUSED, const char *arg) {
05564 struct character *ch;
05565 char act[64];
05566 char tmp[64];
05567 unsigned ch_id;
05568
05569 assert(arg != NULL);
05570
05571 arg=util_getword(arg, act, sizeof act);
05572 if(!strcasecmp(act, "new")) {
05573 ch=character.new();
05574 telnetclient_printf(cl, "Created character %s.\n", character.attr_get(ch, "id"));
05575 character.put(ch);
05576 } else if(!strcasecmp(act, "get")) {
05577 arg=util_getword(arg, tmp, sizeof tmp);
05578 ch_id=strtoul(tmp, 0, 10);
05579 ch=character.get(ch_id);
05580 if(ch) {
05581
05582 arg=util_getword(arg, tmp, sizeof tmp);
05583 telnetclient_printf(cl, "Character %u \"%s\" = \"%s\"\n", ch_id, tmp, character.attr_get(ch, tmp));
05584 character.put(ch);
05585 } else {
05586 telnetclient_printf(cl, "Unknown character \"%s\"\n", tmp);
05587 }
05588 } else if(!strcasecmp(act, "set")) {
05589 arg=util_getword(arg, tmp, sizeof tmp);
05590 ch_id=strtoul(tmp, 0, 10);
05591 ch=character.get(ch_id);
05592 if(ch) {
05593
05594 arg=util_getword(arg, tmp, sizeof tmp);
05595
05596 while(*arg && isspace(*arg)) arg++;
05597 if(!character.attr_set(ch, tmp, arg)) {
05598 telnetclient_printf(cl, "Could not set \"%s\" on character %u.\n", tmp, ch_id);
05599 }
05600 character.put(ch);
05601 } else {
05602 telnetclient_printf(cl, "Unknown character \"%s\"\n", tmp);
05603 }
05604 } else {
05605 telnetclient_printf(cl, "unknown action \"%s\"\n", act);
05606 }
05607
05608 return 1;
05609 }
05610
05612 static int command_not_implemented(struct telnetclient *cl, struct user *u UNUSED, const char *cmd UNUSED, const char *arg UNUSED) {
05613 telnetclient_puts(cl, "Not implemented\n");
05614 return 1;
05615 }
05616
05617 static const struct command_table {
05618 char *name;
05619 int (*cb)(struct telnetclient *cl, struct user *u, const char *cmd, const char *arg);
05620 } command_table[] = {
05621 { "who", command_not_implemented },
05622 { "quit", command_do_quit },
05623 { "page", command_not_implemented },
05624 { "say", command_do_say },
05625 { "yell", command_do_yell },
05626 { "emote", command_do_emote },
05627 { "pose", command_do_pose },
05628 { "chsay", command_do_chsay },
05629 { "sayto", command_not_implemented },
05630 { "tell", command_not_implemented },
05631 { "whisper", command_not_implemented },
05632 { "to", command_not_implemented },
05633 { "help", command_not_implemented },
05634 { "spoof", command_not_implemented },
05635 { "roomget", command_do_roomget },
05636 { "char", command_do_character },
05637 };
05638
05642 static const struct command_short_table {
05643 char *shname;
05644 char *name;
05645 } command_short_table[] = {
05646 { ":", "pose" },
05647 { "'", "say" },
05648 { "\"\"", "yell" },
05649 { "\"", "say" },
05650 { ",", "emote" },
05651 { ".", "chsay" },
05652 { ";", "spoof" },
05653 };
05654
05658 static int command_run(struct telnetclient *cl, struct user *u, const char *cmd, const char *arg) {
05659 unsigned i;
05660
05661 for(i=0;i<NR(command_table);i++) {
05662 if(!strcasecmp(cmd, command_table[i].name)) {
05663 return command_table[i].cb(cl, u, cmd, arg);
05664 }
05665 }
05666
05667 telnetclient_puts(cl, mud_config.msg_invalidcommand);
05668 return 0;
05669 }
05670
05674 static int command_execute(struct telnetclient *cl, struct user *u, const char *line) {
05675 char cmd[64];
05676 const char *e, *arg;
05677 unsigned i;
05678
05679 assert(cl != NULL);
05680 assert(line != NULL);
05681
05682 while(*line && isspace(*line)) line++;
05683
05684 TODO("Can we eliminate trailing spaces?");
05685
05686 TODO("can we define these 1 character commands as aliases?");
05687
05688 if(ispunct(line[0])) {
05689 for(i=0;i<NR(command_short_table);i++) {
05690 const char *shname=command_short_table[i].shname;
05691 int shname_len=strlen(shname);
05692 if(!strncmp(line, shname, shname_len)) {
05693
05694 arg=line+shname_len;
05695
05696 while(*arg && isspace(*arg)) arg++;
05697
05698 return command_run(cl, u, command_short_table[i].name, arg);
05699 }
05700 }
05701 }
05702
05703
05704 e=line+strcspn(line, " \t");
05705 arg=*e ? e+1+strspn(e+1, " \t") : e;
05706 while(*arg && isspace(*arg)) arg++;
05707 assert(e >= line);
05708 if((unsigned)(e-line)>sizeof cmd-1) {
05709 DEBUG("Command length %d is too long, truncating\n", e-line);
05710 e=line+sizeof cmd-1;
05711 }
05712 memcpy(cmd, line, (unsigned)(e-line));
05713 cmd[e-line]=0;
05714
05715 TODO("check for \"playername,\" syntax for directed speech");
05716
05717 TODO("check user aliases");
05718
05719 DEBUG("cmd=\"%s\"\n", cmd);
05720
05721 return command_run(cl, u, cmd, arg);
05722 }
05723
05725 static void command_lineinput(struct telnetclient *cl, const char *line) {
05726 assert(cl != NULL);
05727 assert(cl->sh != NULL);
05728 DEBUG("%s:entered command '%s'\n", telnetclient_username(cl), line);
05729
05730
05731 eventlog_commandinput(cl->sh->name, telnetclient_username(cl), line);
05732
05733
05734 command_execute(cl, NULL, line);
05736
05737 if(telnetclient_isstate(cl, command_lineinput, mud_config.command_prompt)) {
05738 telnetclient_setprompt(cl, mud_config.command_prompt);
05739 }
05740 }
05741
05743 static void command_start_lineinput(struct telnetclient *cl) {
05744 telnetclient_printf(cl, "Terminal type: %s\n", cl->terminal.name);
05745 telnetclient_printf(cl, "display size is: %ux%u\n", cl->terminal.width, cl->terminal.height);
05746 telnetclient_start_lineinput(cl, command_lineinput, mud_config.command_prompt);
05747 }
05748
05750 EXPORT void command_start(void *p, long unused2 UNUSED, void *unused3 UNUSED) {
05751 command_start_lineinput(p);
05752 }
05753
05754
05755
05756
05757
05759 static void login_password_lineinput(struct telnetclient *cl, const char *line) {
05760 struct user *u;
05761
05762 assert(cl != NULL);
05763 assert(line != NULL);
05764 assert(cl->state.login.username[0] != '\0');
05765
05766 TODO("complete login process");
05767 DEBUG("Login attempt: Username='%s'\n", cl->state.login.username);
05768
05769 u=user_lookup(cl->state.login.username);
05770 if(u) {
05771
05772 if(sha1crypt_checkpass(u->password_crypt, line)) {
05773 telnetclient_setuser(cl, u);
05774 eventlog_signon(cl->state.login.username, cl->sh->name);
05775 telnetclient_printf(cl, "Hello, %s.\n\n", u->username);
05776 telnetclient_start_menuinput(cl, &gamemenu_main);
05777 return;
05778 }
05779 telnetclient_puts(cl, mud_config.msgfile_badpassword);
05780 } else {
05781 telnetclient_puts(cl, mud_config.msgfile_noaccount);
05782 }
05783
05784
05785 eventlog_login_failattempt(cl->state.login.username, cl->sh->name);
05786
05787
05788 telnetclient_start_menuinput(cl, &gamemenu_login);
05789 }
05790
05792 static void login_password_start(void *p, long unused2 UNUSED, void *unused3 UNUSED) {
05793 struct telnetclient *cl=p;
05794 telnetclient_start_lineinput(cl, login_password_lineinput, "Password: ");
05795 }
05796
05798 static void login_username_lineinput(struct telnetclient *cl, const char *line) {
05799 assert(line != NULL);
05800
05801 telnetclient_clear_statedata(cl);
05802 cl->state_free=0;
05803
05804 while(*line && isspace(*line)) line++;
05805
05806 if(!*line) {
05807 telnetclient_puts(cl, mud_config.msg_invalidusername);
05808 telnetclient_start_menuinput(cl, &gamemenu_login);
05809 return;
05810 }
05811
05812
05813 snprintf(cl->state.login.username, sizeof cl->state.login.username, "%s", line);
05814
05815 login_password_start(cl, 0, 0);
05816 }
05817
05819 static void login_username_start(void *p, long unused2 UNUSED, void *unused3 UNUSED) {
05820 struct telnetclient *cl=p;
05821 telnetclient_start_lineinput(cl, login_username_lineinput, "Username: ");
05822 }
05823
05825 static void signoff(void *p, long unused2 UNUSED, void *unused3 UNUSED) {
05826 struct telnetclient *cl=p;
05827 telnetclient_close(cl);
05828 }
05829
05830
05831
05832
05833 #define FORM_FLAG_HIDDEN 1
05834 #define FORM_FLAG_INVISIBLE 2
05835
05837 static struct form *form_newuser_app;
05838
05840 EXPORT void form_init(struct form *f, const char *title, void (*form_close)(struct telnetclient *cl, struct form_state *fs)) {
05841 LIST_INIT(&f->items);
05842 f->form_title=strdup(title);
05843 f->tail=NULL;
05844 f->form_close=form_close;
05845 f->item_count=0;
05846 f->message=0;
05847 }
05848
05852 EXPORT void form_setmessage(struct form *f, const char *message) {
05853 f->message=message;
05854 }
05855
05857 EXPORT void form_free(struct form *f) {
05858 struct formitem *curr;
05859
05860 TRACE_ENTER();
05861
05862 free(f->form_title);
05863 f->form_title=NULL;
05864
05865 while((curr=LIST_TOP(f->items))) {
05866 LIST_REMOVE(curr, item);
05867 free(curr->name);
05868 free(curr->prompt);
05869 free(curr->description);
05870 #ifndef NDEBUG
05871 memset(curr, 0x55, sizeof *curr);
05872 #endif
05873 free(curr);
05874 }
05875 memset(f, 0x55, sizeof *f);
05876 }
05877
05879 EXPORT void form_additem(struct form *f, unsigned flags, const char *name, const char *prompt, const char *description, int (*form_check)(struct telnetclient *cl, const char *str)) {
05880 struct formitem *newitem;
05881
05882 newitem=malloc(sizeof *newitem);
05883 newitem->name=strdup(name);
05884 newitem->description=strdup(description);
05885 newitem->prompt=strdup(prompt);
05886 newitem->flags=flags;
05887 newitem->form_check=form_check;
05888 newitem->value_index=f->item_count++;
05889
05890 if(f->tail) {
05891 LIST_INSERT_AFTER(f->tail, newitem, item);
05892 } else {
05893 LIST_INSERT_HEAD(&f->items, newitem, item);
05894 }
05895 f->tail=newitem;
05896 }
05897
05899 static struct formitem *form_getitem(struct form *f, const char *name) {
05900 struct formitem *curr;
05901
05902 assert(f != NULL);
05903 assert(name != NULL);
05904
05905 for(curr=LIST_TOP(f->items);curr;curr=LIST_NEXT(curr, item)) {
05906 if(!strcasecmp(curr->name, name)) {
05907
05908 return curr;
05909 }
05910 }
05911 ERROR_FMT("Unknown form variable '%s'\n", name);
05912 return NULL;
05913 }
05914
05918 static const char *form_getvalue(const struct form *f, unsigned nr_value, char **value, const char *name) {
05919 const struct formitem *curr;
05920
05921 assert(f != NULL);
05922 assert(name != NULL);
05923
05924 for(curr=LIST_TOP(f->items);curr;curr=LIST_NEXT(curr, item)) {
05925 if(!strcasecmp(curr->name, name) && curr->value_index<nr_value) {
05926
05927 return value[curr->value_index];
05928 }
05929 }
05930 ERROR_FMT("Unknown form variable '%s'\n", name);
05931 return NULL;
05932 }
05933
05935 static void form_menu_show(struct telnetclient *cl, const struct form *f, struct form_state *fs) {
05936 const struct formitem *curr;
05937 unsigned i;
05938
05939 menu_titledraw(cl, f->form_title, strlen(f->form_title));
05940
05941 for(i=0,curr=LIST_TOP(f->items);curr&&(!fs||i<fs->nr_value);curr=LIST_NEXT(curr, item),i++) {
05942 const char *user_value;
05943
05944
05945 while(curr&&(curr->flags&FORM_FLAG_INVISIBLE)==FORM_FLAG_INVISIBLE)
05946 curr=LIST_NEXT(curr, item);
05947 if(!curr)
05948 break;
05949
05950 user_value=fs ? fs->value[curr->value_index] ? fs->value[curr->value_index] : "" : 0;
05951 if((curr->flags&FORM_FLAG_HIDDEN)==FORM_FLAG_HIDDEN) {
05952 user_value="<hidden>";
05953 }
05954 telnetclient_printf(cl, "%d. %s %s\n", i+1, curr->prompt, user_value ? user_value : "");
05955 }
05956 telnetclient_printf(cl, "A. accept\n");
05957 }
05958
05960 static void form_lineinput(struct telnetclient *cl, const char *line) {
05961 struct form_state *fs=&cl->state.form;
05962 const struct form *f=fs->form;
05963 char **value=&fs->value[fs->curritem->value_index];
05964
05965 assert(f != NULL);
05966 assert(fs->curritem != NULL);
05967
05968 while(*line && isspace(*line)) line++;
05969
05970 if(*line) {
05971
05972 if(fs->curritem->form_check && !fs->curritem->form_check(cl, line)) {
05973 DEBUG("%s:Invalid form input\n", cl->sh->name);
05974 telnetclient_puts(cl, mud_config.msg_tryagain);
05975 telnetclient_setprompt(cl, fs->curritem->prompt);
05976 return;
05977 }
05978 if(*value) {
05979 free(*value);
05980 *value=NULL;
05981 }
05982 *value=strdup(line);
05983 fs->curritem=LIST_NEXT(fs->curritem, item);
05984 if(fs->curritem && (!fs->done || ((fs->curritem->flags&FORM_FLAG_INVISIBLE)==FORM_FLAG_INVISIBLE))) {
05985
05986 telnetclient_puts(cl, fs->curritem->description);
05987 telnetclient_setprompt(cl, fs->curritem->prompt);
05988 } else {
05989 fs->done=1;
05990
05991 form_menu_show(cl, f, fs);
05992 telnetclient_start_lineinput(cl, form_menu_lineinput, mud_config.form_prompt);
05993 }
05994 }
05995 }
05996
05998 static void form_menu_lineinput(struct telnetclient *cl, const char *line) {
05999 struct form_state *fs=&cl->state.form;
06000 const struct form *f=fs->form;
06001 char *endptr;
06002
06003 assert(cl != NULL);
06004 assert(line != NULL);
06005
06006 while(*line && isspace(*line)) line++;
06007
06008 if(tolower(*line)=='a') {
06009 TODO("callback to close out the form");
06010 if(f->form_close) {
06011
06012 f->form_close(cl, fs);
06013 } else {
06014
06015 DEBUG("%s:ERROR:going to main menu\n", cl->sh->name);
06016 telnetclient_puts(cl, mud_config.msg_errormain);
06017 telnetclient_start_menuinput(cl, &gamemenu_login);
06018 }
06019 return;
06020 } else {
06021 long i;
06022 i=strtol(line, &endptr, 10);
06023 if(endptr!=line && i>0) {
06024 for(fs->curritem=LIST_TOP(f->items);fs->curritem;fs->curritem=LIST_NEXT(fs->curritem, item)) {
06025
06026 if((fs->curritem->flags&FORM_FLAG_INVISIBLE)==FORM_FLAG_INVISIBLE) continue;
06027
06028 if(--i==0) {
06029 telnetclient_start_lineinput(cl, form_lineinput, fs->curritem->prompt);
06030 return;
06031 }
06032 }
06033 }
06034 }
06035
06036
06037 telnetclient_puts(cl, mud_config.msg_invalidselection);
06038 form_menu_show(cl, f, fs);
06039 telnetclient_setprompt(cl, mud_config.form_prompt);
06040 return;
06041 }
06042
06044 static void form_state_free(struct telnetclient *cl) {
06045 struct form_state *fs=&cl->state.form;
06046 unsigned i;
06047 DEBUG("%s:freeing state\n", cl->sh->name);
06048
06049 if(fs->value) {
06050 for(i=0;i<fs->nr_value;i++) {
06051 if(fs->value[i]) {
06052 size_t len;
06053 len=strlen(fs->value[i]);
06054 memset(fs->value[i], 0, len);
06055 free(fs->value[i]);
06056 fs->value[i]=NULL;
06057 }
06058 }
06059 free(fs->value);
06060 }
06061 fs->value=0;
06062 fs->nr_value=0;
06063 }
06064
06066 EXPORT void form_state_init(struct form_state *fs, const struct form *f) {
06067 fs->form=f;
06068 fs->nr_value=0;
06069 fs->value=NULL;
06070 fs->done=0;
06071 }
06072
06074 static int form_createaccount_username_check(struct telnetclient *cl, const char *str) {
06075 int res;
06076 size_t len;
06077 const char *s;
06078
06079 TRACE_ENTER();
06080
06081 assert(cl != NULL);
06082
06083 len=strlen(str);
06084 if(len<3) {
06085 telnetclient_puts(cl, mud_config.msg_usermin3);
06086 DEBUG_MSG("failure: username too short.");
06087 goto failure;
06088 }
06089
06090 for(s=str,res=isalpha(*s);*s;s++) {
06091 res=res&&isalnum(*s);
06092 if(!res) {
06093 telnetclient_puts(cl, mud_config.msg_useralphanumeric);
06094 DEBUG_MSG("failure: bad characters");
06095 goto failure;
06096 }
06097 }
06098
06099 if(user_exists(str)) {
06100 telnetclient_puts(cl, mud_config.msg_userexists);
06101 DEBUG_MSG("failure: user exists.");
06102 goto failure;
06103 }
06104
06105 DEBUG_MSG("success.");
06106 return 1;
06107 failure:
06108 telnetclient_puts(cl, mud_config.msg_tryagain);
06109 telnetclient_setprompt(cl, cl->state.form.curritem->prompt);
06110 return 0;
06111 }
06112
06113 static int form_createaccount_password_check(struct telnetclient *cl, const char *str) {
06114 TRACE_ENTER();
06115
06116 assert(cl != NULL);
06117 assert(cl->state.form.form != NULL);
06118
06119 if(str && strlen(str)>3) {
06120 DEBUG_MSG("success.");
06121 return 1;
06122 }
06123
06124
06125 telnetclient_puts(cl, mud_config.msg_tryagain);
06126 telnetclient_setprompt(cl, cl->state.form.curritem->prompt);
06127 return 0;
06128 }
06129
06131 static int form_createaccount_password2_check(struct telnetclient *cl, const char *str) {
06132 const char *password1;
06133 struct form_state *fs=&cl->state.form;
06134
06135 TRACE_ENTER();
06136
06137 assert(cl != NULL);
06138 assert(fs->form != NULL);
06139
06140 password1=form_getvalue(fs->form, fs->nr_value, fs->value, "PASSWORD");
06141 if(password1 && !strcmp(password1, str)) {
06142 DEBUG_MSG("success.");
06143 return 1;
06144 }
06145
06146 telnetclient_puts(cl, mud_config.msg_tryagain);
06147 fs->curritem=form_getitem((struct form*)fs->form, "PASSWORD");
06148 telnetclient_setprompt(cl, fs->curritem->prompt);
06149 return 0;
06150 }
06151
06153 static void form_createaccount_close(struct telnetclient *cl, struct form_state *fs) {
06154 const char *username, *password, *email;
06155 struct user *u;
06156 const struct form *f=fs->form;
06157
06158 username=form_getvalue(f, fs->nr_value, fs->value, "USERNAME");
06159 password=form_getvalue(f, fs->nr_value, fs->value, "PASSWORD");
06160 email=form_getvalue(f, fs->nr_value, fs->value, "EMAIL");
06161
06162 DEBUG("%s:create account: '%s'\n", cl->sh->name, username);
06163
06164 if(user_exists(username)) {
06165 telnetclient_puts(cl, mud_config.msg_userexists);
06166 return;
06167 }
06168
06169 u=user_create(username, password, email);
06170 if(!u) {
06171 telnetclient_printf(cl, "Could not create user named '%s'\n", username);
06172 return;
06173 }
06174 user_free(u);
06175
06176 telnetclient_puts(cl, mud_config.msg_usercreatesuccess);
06177
06178 TODO("for approvable based systems, disconnect the user with a friendly message");
06179 telnetclient_start_menuinput(cl, &gamemenu_login);
06180 }
06181
06183 static void form_start(void *p, long unused2 UNUSED, void *form) {
06184 struct telnetclient *cl=p;
06185 struct form *f=form;
06186 struct form_state *fs=&cl->state.form;
06187
06188 telnetclient_clear_statedata(cl);
06189
06190 if(!mud_config.newuser_allowed) {
06191
06192 telnetclient_puts(cl, mud_config.msgfile_newuser_deny);
06193 telnetclient_start_menuinput(cl, &gamemenu_login);
06194 return;
06195 }
06196
06197 if(f->message)
06198 telnetclient_puts(cl, f->message);
06199
06200 cl->state_free=form_state_free;
06201 fs->form=f;
06202 fs->curritem=LIST_TOP(f->items);
06203 fs->nr_value=f->item_count;
06204 fs->value=calloc(fs->nr_value, sizeof *fs->value);
06205
06206 menu_titledraw(cl, f->form_title, strlen(f->form_title));
06207
06208 telnetclient_puts(cl, fs->curritem->description);
06209 telnetclient_start_lineinput(cl, form_lineinput, fs->curritem->prompt);
06210 }
06211
06213 static void form_createaccount_start(void *p, long unused2 UNUSED, void *unused3 UNUSED) {
06214 form_start(p, 0, form_newuser_app);
06215 }
06216
06218 EXPORT struct form *form_load(const char *buf, void (*form_close)(struct telnetclient *cl, struct form_state *fs)) {
06219 const char *p, *tmp;
06220 char *name, *prompt, *description, *title;
06221 struct form *f;
06222 struct util_strfile h;
06223 size_t e, len;
06224
06225 name=0;
06226 prompt=0;
06227 description=0;
06228 f=0;
06229
06230 util_strfile_open(&h, buf);
06231
06232 p=util_strfile_readline(&h, &len);
06233 if(!p) {
06234 ERROR_MSG("Could not parse form.");
06235 goto failure;
06236 }
06237 title=malloc(len+1);
06238 memcpy(title, p, len);
06239 title[len]=0;
06240
06241 f=calloc(1, sizeof *f);
06242 form_init(f, title, form_close);
06243
06244 free(title);
06245 title=NULL;
06246
06247
06248 while(1) {
06249
06250
06251 do {
06252 p=util_strfile_readline(&h, &len);
06253 if(!p)
06254 goto done;
06255 while(isspace(*p)) p++ ;
06256 for(e=0;e<len && !isspace(p[e]);e++) ;
06257 } while(!e);
06258
06259 name=malloc(e+1);
06260 memcpy(name, p, e);
06261 name[e]=0;
06262
06263
06264 p=util_strfile_readline(&h, &len);
06265 if(!p) break;
06266 prompt=malloc(len+1);
06267 memcpy(prompt, p, len);
06268 prompt[len]=0;
06269
06270
06271 tmp=strstr(h.buf, "\n~");
06272 if(!tmp)
06273 tmp=strlen(h.buf)+h.buf;
06274 else
06275 tmp++;
06276
06277 len=tmp-h.buf;
06278 description=malloc(len+1);
06279 memcpy(description, h.buf, len);
06280 description[len]=0;
06281 h.buf=*tmp?tmp+1:tmp;
06282
06283 DEBUG("name='%s'\n", name);
06284 DEBUG("prompt='%s'\n", prompt);
06285 DEBUG("description='%s'\n", description);
06286 form_additem(f, 0, name, prompt, description, NULL);
06287 free(name);
06288 name=0;
06289 free(prompt);
06290 prompt=0;
06291 free(description);
06292 description=0;
06293 }
06294 done:
06295 util_strfile_close(&h);
06296 free(name);
06297 free(prompt);
06298 free(description);
06299 return f;
06300 failure:
06301 ERROR_MSG("Error loading form");
06302 util_strfile_close(&h);
06303 free(name);
06304 free(prompt);
06305 free(description);
06306 if(f) {
06307 form_free(f);
06308 }
06309 return NULL;
06310 }
06311
06313 EXPORT struct form *form_load_from_file(const char *filename, void (*form_close)(struct telnetclient *cl, struct form_state *fs)) {
06314 struct form *ret;
06315 char *buf;
06316
06317 buf=util_textfile_load(filename);
06318 if(!buf) return 0;
06319 ret=form_load(buf, form_close);
06320 free(buf);
06321 return ret;
06322 }
06323
06325 EXPORT int form_module_init(void) {
06326 struct formitem *fi;
06327
06328 form_newuser_app=form_load_from_file(mud_config.form_newuser_filename, form_createaccount_close);
06329 if(!form_newuser_app) {
06330 ERROR_FMT("could not load %s\n", mud_config.form_newuser_filename);
06331 return 0;
06332 }
06333
06334 fi=form_getitem(form_newuser_app, "USERNAME");
06335 if(!fi) {
06336 ERROR_FMT("%s does not have a USERNAME field.\n", mud_config.form_newuser_filename);
06337 return 0;
06338 }
06339 fi->form_check=form_createaccount_username_check;
06340
06341 fi=form_getitem(form_newuser_app, "PASSWORD");
06342 if(!fi) {
06343 ERROR_FMT("%s does not have a PASSWORD field.\n", mud_config.form_newuser_filename);
06344 return 0;
06345 }
06346 fi->flags|=FORM_FLAG_HIDDEN;
06347 fi->form_check=form_createaccount_password_check;
06348
06349 fi=form_getitem(form_newuser_app, "PASSWORD2");
06350 if(!fi) {
06351 VERBOSE("warning: %s does not have a PASSWORD2 field.\n", mud_config.form_newuser_filename);
06352 return 0;
06353 } else {
06354 fi->flags|=FORM_FLAG_INVISIBLE;
06355 fi->form_check=form_createaccount_password2_check;
06356 }
06357
06358 return 1;
06359 }
06360
06362 EXPORT void form_module_shutdown(void) {
06363 form_free(form_newuser_app);
06364 free(form_newuser_app);
06365 form_newuser_app=NULL;
06366 }
06367
06368
06369
06370
06371
06373 EXPORT int game_init(void) {
06374
06375
06376 menu_create(&gamemenu_login, "Login Menu");
06377
06378 menu_additem(&gamemenu_login, 'L', "Login", login_username_start, 0, NULL);
06379 menu_additem(&gamemenu_login, 'N', "New User", form_createaccount_start, 0, NULL);
06380 menu_additem(&gamemenu_login, 'Q', "Disconnect", signoff, 0, NULL);
06381
06382 menu_create(&gamemenu_main, "Main Menu");
06383 menu_additem(&gamemenu_main, 'E', "Enter the game", command_start, 0, NULL);
06384
06385 menu_additem(&gamemenu_main, 'B', "Back to login menu", menu_start, 0, &gamemenu_login);
06386 menu_additem(&gamemenu_main, 'Q', "Disconnect", signoff, 0, NULL);
06387 return 1;
06388 }
06389
06390
06391
06392
06393
06399 struct webserver {
06400 struct socketio_handle *sh;
06420 };
06421
06425 static struct socketio_handle *webserver_listen_handle;
06426
06430 static void webserver_close(struct webserver *ws) {
06431 if(ws && ws->sh && !ws->sh->delete_flag) {
06432 ws->sh->delete_flag=1;
06433 socketio_delete_count++;
06434 }
06435 }
06436
06440 static void webserver_read_event(struct socketio_handle *sh, SOCKET fd, void *extra) {
06441 struct webserver *ws=extra;
06442 int res;
06443 char data[60];
06444 const size_t len=sizeof data;
06446 assert(sh != NULL);
06447 assert(ws != NULL);
06448 assert(fd != INVALID_SOCKET);
06449 assert(!sh->delete_flag);
06450
06451 res=socketio_recv(fd, data, len);
06452 if(res<=0) {
06453
06454 webserver_close(ws);
06455 return;
06456 }
06457
06460 eventlog_webserver_get(sh->name, "/");
06462
06463
06464
06465
06466
06467 socketio_writeready(fd);
06468
06469
06470 socketio_readready(fd);
06471 }
06472
06476 static void webserver_write_event(struct socketio_handle *sh, SOCKET fd, void *extra) {
06477 struct webserver *ws=extra;
06478 int res;
06479 const char data[]=
06480 "HTTP/1.1 200 OK\r\n"
06481 "Connection: close\r\n"
06482 "Content-Type: text/plain\r\n"
06483 "\r\n"
06484 "Hello World. This is my webserver!\r\n";
06485
06486 assert(sh != NULL);
06487 assert(ws != NULL);
06488 assert(fd != INVALID_SOCKET);
06489 assert(!sh->delete_flag);
06490
06491 res=socketio_send(fd, data, strlen(data));
06492 if(res<0) {
06493 sh->delete_flag=1;
06494 return;
06495 }
06496
06503 webserver_close(ws);
06504 }
06505
06509 static void webserver_free(struct socketio_handle *sh, void *p) {
06510 struct webserver *ws=p;
06511
06512 if(sh->fd!=INVALID_SOCKET) {
06513
06514 socketio_readready(sh->fd);
06515 }
06516
06517 if(!sh->delete_flag) {
06518 ERROR_MSG("WARNING: delete_flag was not set before freeing");
06519 }
06520
06521
06522 sh->extra=NULL;
06523 ws->sh=NULL;
06524
06525 free(ws);
06526 }
06527
06531 static struct webserver *webserver_newclient(struct socketio_handle *sh) {
06532 struct webserver *ws;
06533 ws=calloc(1, sizeof *ws);
06534 ws->sh=sh;
06535
06536 sh->extra=ws;
06537 sh->extra_free=webserver_free;
06538
06539 sh->write_event=webserver_write_event;
06540 sh->read_event=webserver_read_event;
06541
06542
06543 socketio_readready(sh->fd);
06544
06545 return ws;
06546 }
06547
06551 static void webserver_new_event(struct socketio_handle *sh) {
06552 struct webserver *ws;
06554 ws=webserver_newclient(sh);
06555
06556 }
06557
06561 EXPORT int webserver_init(int family, unsigned port) {
06562 char port_str[16];
06563 snprintf(port_str, sizeof port_str, "%u", port);
06564 webserver_listen_handle=socketio_listen(family, SOCK_STREAM, NULL, port_str, webserver_new_event);
06565 if(!webserver_listen_handle) {
06566 return 0;
06567 }
06568
06569 return 1;
06570 }
06571
06575 EXPORT void webserver_shutdown(void) {
06576 if(webserver_listen_handle) {
06577 webserver_listen_handle->delete_flag=1;
06578 socketio_delete_count++;
06579 webserver_listen_handle=NULL;
06580 }
06581 }
06582
06583
06584
06585
06586
06588 static int fl_default_family=0;
06589
06591 static int do_config_prompt(struct config *cfg UNUSED, void *extra UNUSED, const char *id, const char *value) {
06592 char **target;
06593 size_t len;
06594
06595 if(!strcasecmp(id, "prompt.menu")) {
06596 target=&mud_config.menu_prompt;
06597 } else if(!strcasecmp(id, "prompt.form")) {
06598 target=&mud_config.form_prompt;
06599 } else if(!strcasecmp(id, "prompt.command")) {
06600 target=&mud_config.command_prompt;
06601 } else {
06602 ERROR_FMT("problem with config option '%s' = '%s'\n", id, value);
06603 return 1;
06604 }
06605
06606 free(*target);
06607 len=strlen(value)+2;
06608 *target=malloc(len);
06609 snprintf(*target, len, "%s ", value);
06610 return 0;
06611 }
06612
06614 static int do_config_msg(struct config *cfg UNUSED, void *extra UNUSED, const char *id, const char *value) {
06615 size_t len;
06616 unsigned i;
06617 const struct {
06618 const char *id;
06619 char **target;
06620 } info[] = {
06621 { "msg.unsupported", &mud_config.msg_unsupported },
06622 { "msg.invalidselection", &mud_config.msg_invalidselection },
06623 { "msg.invalidusername", &mud_config.msg_invalidusername },
06624 { "msg.tryagain", &mud_config.msg_tryagain },
06625 { "msg.errormain", &mud_config.msg_errormain },
06626 { "msg.usermin3", &mud_config.msg_usermin3 },
06627 { "msg.invalidcommand", &mud_config.msg_invalidcommand },
06628 { "msg.useralphanumeric", &mud_config.msg_useralphanumeric },
06629 { "msg.userexists", &mud_config.msg_userexists },
06630 { "msg.usercreatesuccess", &mud_config.msg_usercreatesuccess },
06631 };
06632
06633 for(i=0;i<NR(info);i++) {
06634 if(!strcasecmp(id, info[i].id)) {
06635 free(*info[i].target);
06636 len=strlen(value)+2;
06637 *info[i].target=malloc(len);
06638 snprintf(*info[i].target, len, "%s\n", value);
06639 return 0;
06640 }
06641 }
06642 ERROR_FMT("problem with config option '%s' = '%s'\n", id, value);
06643 return 1;
06644 }
06645
06647 static int do_config_msgfile(struct config *cfg UNUSED, void *extra UNUSED, const char *id, const char *value) {
06648 unsigned i;
06649 const struct {
06650 const char *id;
06651 char **target;
06652 } info[] = {
06653 { "msgfile.noaccount", &mud_config.msgfile_noaccount },
06654 { "msgfile.badpassword", &mud_config.msgfile_badpassword },
06655 { "msgfile.welcome", &mud_config.msgfile_welcome },
06656 { "msgfile.newuser_create", &mud_config.msgfile_newuser_create },
06657 { "msgfile.newuser_deny", &mud_config.msgfile_newuser_deny },
06658 };
06659
06660 for(i=0;i<NR(info);i++) {
06661 if(!strcasecmp(id, info[i].id)) {
06662 free(*info[i].target);
06663 *info[i].target=util_textfile_load(value);
06664
06665
06666 if(!*info[i].target) {
06667 char buf[128];
06668 snprintf(buf, sizeof buf, "<<fileNotFound:%s>>\n", value);
06669 *info[i].target=strdup(buf);
06670 }
06671 return 0;
06672 }
06673 }
06674 ERROR_FMT("problem with config option '%s' = '%s'\n", id, value);
06675 return 1;
06676 }
06677
06679 static int do_config_string(struct config *cfg UNUSED, void *extra, const char *id UNUSED, const char *value) {
06680 char **target=extra;
06681 assert(value != NULL);
06682 assert(target != NULL);
06683
06684 free(*target);
06685 *target=strdup(value);
06686 return 0;
06687 }
06688
06692 static int do_config_port(struct config *cfg UNUSED, void *extra UNUSED, const char *id, const char *value) {
06693 if(!socketio_listen(fl_default_family, SOCK_STREAM, NULL, value, telnetclient_new_event)) {
06694 ERROR_FMT("problem with config option '%s' = '%s'\n", id, value);
06695 return 1;
06696 }
06697 return 0;
06698 }
06699
06701 static int do_config_uint(struct config *cfg UNUSED, void *extra, const char *id UNUSED, const char *value) {
06702 char *endptr;
06703 unsigned *uint_p=extra;
06704 assert(extra != NULL);
06705 if(!extra) return -1;
06706
06707 if(!*value) {
06708 DEBUG_MSG("Empty string");
06709 return -1;
06710 }
06711 *uint_p=strtoul(value, &endptr, 0);
06712
06713 if(*endptr!=0) {
06714 DEBUG_MSG("Not a number");
06715 return -1;
06716 }
06717
06718 return 0;
06719 }
06720
06724 EXPORT void mud_config_init(void) {
06725 mud_config.config_filename=strdup("boris.cfg");
06726 mud_config.menu_prompt=strdup("Selection: ");
06727 mud_config.form_prompt=strdup("Selection: ");
06728 mud_config.command_prompt=strdup("> ");
06729 mud_config.msg_errormain=strdup("ERROR: going back to main menu!\n");
06730 mud_config.msg_invalidselection=strdup("Invalid selection!\n");
06731 mud_config.msg_invalidusername=strdup("Invalid username\n");
06732 mud_config.msgfile_noaccount=strdup("\nInvalid password or account not found!\n\n");
06733 mud_config.msgfile_badpassword=strdup("\nInvalid password or account not found!\n\n");
06734 mud_config.msg_tryagain=strdup("Try again!\n");
06735 mud_config.msg_unsupported=strdup("Not supported!\n");
06736 mud_config.msg_useralphanumeric=strdup("Username must only contain alphanumeric characters and must start with a letter!\n");
06737 mud_config.msg_usercreatesuccess=strdup("Account successfully created!\n");
06738 mud_config.msg_userexists=strdup("Username already exists!\n");
06739 mud_config.msg_usermin3=strdup("Username must contain at least 3 characters!\n");
06740 mud_config.msg_invalidcommand=strdup("Invalid command!\n");
06741 mud_config.msgfile_welcome=strdup("Welcome\n\n");
06742 mud_config.newuser_level=5;
06743 mud_config.newuser_flags=0;
06744 mud_config.newuser_allowed=0;
06745 mud_config.eventlog_filename=strdup("boris.log\n");
06746 mud_config.eventlog_timeformat=strdup("%y%m%d-%H%M");
06747 mud_config.msgfile_newuser_create=strdup("\nPlease enter only correct information in this application.\n\n");
06748 mud_config.msgfile_newuser_deny=strdup("\nNot accepting new user applications!\n\n");
06749 mud_config.default_channels=strdup("@system,@wiz,OOC,auction,chat,newbie");
06750 mud_config.webserver_port=0;
06751 mud_config.form_newuser_filename=strdup("data/forms/newuser.form");
06752 mud_config.plugins=NULL;
06753 }
06754
06758 EXPORT void mud_config_shutdown(void) {
06759 char **targets[] = {
06760 &mud_config.menu_prompt,
06761 &mud_config.form_prompt,
06762 &mud_config.command_prompt,
06763 &mud_config.msg_errormain,
06764 &mud_config.msg_invalidselection,
06765 &mud_config.msg_invalidusername,
06766 &mud_config.msgfile_noaccount,
06767 &mud_config.msgfile_badpassword,
06768 &mud_config.msg_tryagain,
06769 &mud_config.msg_unsupported,
06770 &mud_config.msg_useralphanumeric,
06771 &mud_config.msg_usercreatesuccess,
06772 &mud_config.msg_userexists,
06773 &mud_config.msg_usermin3,
06774 &mud_config.msg_invalidcommand,
06775 &mud_config.msgfile_welcome,
06776 &mud_config.eventlog_filename,
06777 &mud_config.eventlog_timeformat,
06778 &mud_config.msgfile_newuser_create,
06779 &mud_config.msgfile_newuser_deny,
06780 &mud_config.default_channels,
06781 &mud_config.form_newuser_filename,
06782 &mud_config.plugins,
06783 };
06784 unsigned i;
06785 for(i=0;i<NR(targets);i++) {
06786 free(*targets[i]);
06787 *targets[i]=NULL;
06788 }
06789 }
06790
06795 EXPORT int mud_config_process(void) {
06796 struct config cfg;
06797 config_setup(&cfg);
06798 config_watch(&cfg, "server.port", do_config_port, 0);
06799 config_watch(&cfg, "server.plugins", do_config_string, &mud_config.plugins);
06800 config_watch(&cfg, "prompt.*", do_config_prompt, 0);
06801 config_watch(&cfg, "msg.*", do_config_msg, 0);
06802 config_watch(&cfg, "msgfile.*", do_config_msgfile, 0);
06803 config_watch(&cfg, "newuser.level", do_config_uint, &mud_config.newuser_level);
06804 config_watch(&cfg, "newuser.allowed", do_config_uint, &mud_config.newuser_allowed);
06805 config_watch(&cfg, "newuser.flags", do_config_uint, &mud_config.newuser_flags);
06806 config_watch(&cfg, "eventlog.filename", do_config_string, &mud_config.eventlog_filename);
06807 config_watch(&cfg, "eventlog.timeformat", do_config_string, &mud_config.eventlog_timeformat);
06808 config_watch(&cfg, "channels.default", do_config_string, &mud_config.default_channels);
06809 config_watch(&cfg, "webserver.port", do_config_uint, &mud_config.webserver_port);
06810 config_watch(&cfg, "form.newuser.filename", do_config_string, &mud_config.form_newuser_filename);
06811 #if !defined(NDEBUG) && !defined(NTEST)
06812 config_watch(&cfg, "*", config_test_show, 0);
06813 #endif
06814 if(!config_load(mud_config.config_filename, &cfg)) {
06815 config_free(&cfg);
06816 return 0;
06817 }
06818 config_free(&cfg);
06819 return 1;
06820 }
06821
06822
06823
06824
06825
06826 #define PLUGIN_NAME_MAX 64
06827
06828 struct plugin {
06829 LIST_ENTRY(struct plugin) list;
06830 dll_handle_t h;
06831 char *name;
06832 const struct plugin_basic_class *plugin_class;
06833 };
06834
06835 LIST_HEAD(struct plugin_list, struct plugin);
06836 static struct plugin_list plugin_list;
06837
06838 static struct plugin *plugin_find(const char *name) {
06839 struct plugin *curr;
06840 assert(name != NULL);
06841 for(curr=LIST_TOP(plugin_list);curr;curr=LIST_NEXT(curr, list)) {
06842 assert(curr->name != NULL);
06843 if(!strcasecmp(name, curr->name)) {
06844 return curr;
06845 }
06846 }
06847 return NULL;
06848 }
06849
06853 EXPORT int plugin_load(const char *name) {
06854 struct plugin *pi;
06855 dll_handle_t h;
06856 const struct plugin_basic_class *plugin_class;
06857 char path[PATH_MAX];
06858
06859
06860 pi=plugin_find(name);
06861 if(pi) {
06862 ERROR_FMT("plugin already loaded: %s\n", name);
06863 return 0;
06864 }
06865
06866
06867 snprintf(path, sizeof path, "./%s", name);
06868
06869
06870 if(!dll_open(&h, path)) {
06871 ERROR_FMT("could not open plugin: %s\n", name);
06872 return 0;
06873 }
06874
06875
06876 plugin_class=dll_symbol(h, "plugin_class");
06877 if(!plugin_class || plugin_class->api_version!=PLUGIN_API || !plugin_class->initialize) {
06878 dll_close(h);
06879 ERROR_FMT("could not get class from plugin: %s\n", name);
06880 return 0;
06881 }
06882
06883
06884 if(!plugin_class->initialize()) {
06885 dll_close(h);
06886 ERROR_FMT("could not initialize plugin: %s\n", name);
06887 return 0;
06888 }
06889
06890
06891 pi=calloc(1, sizeof *pi);
06892 pi->h=h;
06893 pi->name=strdup(name);
06894 pi->plugin_class=plugin_class;
06895 LIST_INSERT_HEAD(&plugin_list, pi, list);
06896
06897 VERBOSE("Loaded plugin: %s\n", name);
06898 return 1;
06899 }
06900
06905 EXPORT int plugin_load_list(const char *list) {
06906 char name[PLUGIN_NAME_MAX];
06908 while(*list) {
06909 const char *e;
06910
06911 while(*list && isspace(*list)) list++;
06912 for(e=list;*e && !isspace(*e);e++) ;
06913
06914 snprintf(name, sizeof name, "%.*s", (int)(e-list), list);
06915
06916 list=e;
06917 if(*list) list++;
06918 if(!plugin_load(name)) {
06919 return 0;
06920 }
06921 }
06922 return 1;
06923 }
06924
06925
06926
06927
06928
06929 void show_version(void) {
06930 puts("Version " BORIS_VERSION_STR " (built " __DATE__ ")");
06931 }
06932
06936 static sig_atomic_t keep_going_fl=1;
06937
06941 static void sh_quit(int s UNUSED) {
06942 keep_going_fl=0;
06943 }
06944
06948 static void usage(void) {
06949 fprintf(stderr,
06950 "usage: boris [-h46] [-p port]\n"
06951 "-4 use IPv4-only server addresses\n"
06952 "-6 use IPv6-only server addresses\n"
06953 "-h help\n"
06954 );
06955 exit(EXIT_FAILURE);
06956 }
06957
06963 static void need_parameter(int ch, const char *next_arg) {
06964 if(!next_arg) {
06965 ERROR_FMT("option -%c takes a parameter\n", ch);
06966 usage();
06967 }
06968 }
06969
06977 static int process_flag(int ch, const char *next_arg) {
06978 switch(ch) {
06979 case '4':
06980 fl_default_family=AF_INET;
06981 return 0;
06982 case '6':
06983 fl_default_family=AF_INET6;
06984 return 0;
06985 case 'c':
06986 need_parameter(ch, next_arg);
06987 free(mud_config.config_filename);
06988 mud_config.config_filename=strdup(next_arg);
06989 return 1;
06990 case 'p':
06991 need_parameter(ch, next_arg);
06992 if(!socketio_listen(fl_default_family, SOCK_STREAM, NULL, next_arg, telnetclient_new_event)) {
06993 usage();
06994 }
06995 return 1;
06996 case 'V':
06997 show_version();
06998 exit(0);
06999 return 0;
07000 default:
07001 ERROR_FMT("Unknown option -%c\n", ch);
07002 case 'h':
07003 usage();
07004 }
07005 return 0;
07006 }
07007
07013 static void process_args(int argc, char **argv) {
07014 int i, j;
07015
07016 for(i=1;i<argc;i++) {
07017 if(argv[i][0]=='-') {
07018 for(j=1;argv[i][j];j++) {
07019 if(process_flag(argv[i][j], (i+1)<argc ? argv[i+1] : NULL)) {
07020
07021 i++;
07022 break;
07023 }
07024 }
07025 } else {
07026 TODO("process arguments");
07027 fprintf(stderr, "TODO: process argument '%s'\n", argv[i]);
07028 }
07029 }
07030 }
07031
07035 int main(int argc, char **argv) {
07036 show_version();
07037
07038 signal(SIGINT, sh_quit);
07039 signal(SIGTERM, sh_quit);
07040
07041 #ifndef NTEST
07042 acs_test();
07043 config_test();
07044 bitmap_test();
07045 freelist_test();
07046 heapqueue_test();
07047 sha1_test();
07048 sha1crypt_test();
07049 #endif
07050
07051 srand((unsigned)time(NULL));
07052
07053 if(MKDIR("data")==-1 && errno!=EEXIST) {
07054 PERROR("data/");
07055 return EXIT_FAILURE;
07056 }
07057
07058 if(!socketio_init()) {
07059 return EXIT_FAILURE;
07060 }
07061 atexit(socketio_shutdown);
07062
07063
07064 mud_config_init();
07065 atexit(mud_config_shutdown);
07066
07067
07068 process_args(argc, argv);
07069
07070
07071 if(!mud_config_process()) {
07072 ERROR_MSG("could not load configuration");
07073 return EXIT_FAILURE;
07074 }
07075
07076 if(!plugin_load_list(mud_config.plugins)) {
07077 ERROR_MSG("could not load one or more plugins");
07078 return EXIT_FAILURE;
07079 }
07080
07081
07082
07083 if(!room_owner) {
07084 b_log(B_LOG_CRIT, "room", "No room system loaded!");
07085 return EXIT_FAILURE;
07086 }
07087 if(!character_owner) {
07088 b_log(B_LOG_CRIT, "character", "No character system loaded!");
07089 return EXIT_FAILURE;
07090 }
07091 if(!channel_owner) {
07092 b_log(B_LOG_CRIT, "channel", "No channel system loaded!");
07093 return EXIT_FAILURE;
07094 }
07095
07096 if(!eventlog_init()) {
07097 return EXIT_FAILURE;
07098 }
07099 atexit(eventlog_shutdown);
07100
07101 if(!user_init()) {
07102 ERROR_MSG("could not initialize users");
07103 return EXIT_FAILURE;
07104 }
07105 atexit(user_shutdown);
07106
07107 if(!form_module_init()) {
07108 ERROR_MSG("could not initialize forms");
07109 return EXIT_FAILURE;
07110 }
07111 atexit(form_module_shutdown);
07112
07113
07114 if(mud_config.webserver_port) {
07115 if(!webserver_init(fl_default_family, mud_config.webserver_port)) {
07116 ERROR_MSG("could not initialize webserver");
07117 return EXIT_FAILURE;
07118 }
07119 atexit(webserver_shutdown);
07120 }
07121
07122 if(!game_init()) {
07123 ERROR_MSG("could not start game");
07124 return EXIT_FAILURE;
07125 }
07126
07127 eventlog_server_startup();
07128
07129 TODO("use the next event for the timer");
07130 while(keep_going_fl) {
07131 telnetclient_prompt_refresh_all();
07132 if(!socketio_dispatch(-1))
07133 break;
07134 fprintf(stderr, "Tick\n");
07135 }
07136
07137 eventlog_server_shutdown();
07138 fprintf(stderr, "Server shutting down.\n");
07139 return 0;
07140 }
07141
07142
07143
07144