2 Copyright (c) 1993 Richard V. Nash.
3 Copyright (c) 2000 Dan Papasian
4 Copyright (C) Andrew Tridgell 2002
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 int safestring(char *str);
26 char *eatword(char *str)
28 while (*str && !isspace(*str))
33 char *eatwhite(char *str)
35 while (*str && isspace(*str))
40 char *eattailwhite(char *str)
47 while (len > 0 && isspace(str[len - 1]))
53 char *nextword(char *str)
55 return eatwhite(eatword(str));
58 int mail_string_to_address(char *addr, char *subj, char *str)
61 char template[] = SPOOL_DIR;
63 fd = mkstemp(template);
65 d_printf("Failed to create spool file\n");
69 dprintf(fd, "To: %s\nSubject: %s\n\n%s\n", addr, subj, str);
75 int mail_string_to_user(int p, char *subj, char *str)
77 struct player *pp = &player_globals.parray[p];
78 if (pp->emailAddress &&
79 pp->emailAddress[0] &&
80 safestring(pp->emailAddress)) {
81 return mail_string_to_address(pp->emailAddress, subj, str);
87 /* Process a command for a user */
88 int pcommand(int p, char *comstr,...)
90 struct player *pp = &player_globals.parray[p];
93 int current_socket = pp->socket;
97 vasprintf(&tmp, comstr, ap);
99 retval = process_input(current_socket, tmp);
101 if (retval == COM_LOGOUT) {
102 process_disconnection(current_socket);
103 net_close_connection(current_socket);
108 static int vpprintf(int p, int do_formatting, char *format,va_list ap)
110 struct player *pp = &player_globals.parray[p];
114 retval = vasprintf(&tmp, format, ap);
116 net_send_string(pp->socket,
128 int pprintf(int p, char *format,...)
132 va_start(ap, format);
133 retval = vpprintf(p, 1, format, ap);
138 static void pprintf_dohightlight(int p)
140 struct player *pp = &player_globals.parray[p];
141 if (pp->highlight & 0x01)
142 pprintf(p, "\033[7m");
143 if (pp->highlight & 0x02)
144 pprintf(p, "\033[1m");
145 if (pp->highlight & 0x04)
146 pprintf(p, "\033[4m");
147 if (pp->highlight & 0x08)
148 pprintf(p, "\033[2m");
151 int pprintf_highlight(int p, char *format,...)
153 struct player *pp = &player_globals.parray[p];
157 pprintf_dohightlight(p);
158 va_start(ap, format);
159 retval = vpprintf(p, 1, format, ap);
162 pprintf(p, "\033[0m");
166 static void sprintf_dohightlight(int p, char *s)
168 struct player *pp = &player_globals.parray[p];
169 if (pp->highlight & 0x01)
170 strcat(s, "\033[7m");
171 if (pp->highlight & 0x02)
172 strcat(s, "\033[1m");
173 if (pp->highlight & 0x04)
174 strcat(s, "\033[4m");
175 if (pp->highlight & 0x08)
176 strcat(s, "\033[2m");
180 like pprintf() but with paging for long messages
182 int pprintf_more(int p, char *format,...)
184 struct player *pp = &player_globals.parray[p];
187 va_start(ap, format);
188 vasprintf(&s, format, ap);
194 return pmore_text(p);
197 int psprintf_highlight(int p, char *s, char *format,...)
199 struct player *pp = &player_globals.parray[p];
203 va_start(ap, format);
205 sprintf_dohightlight(p, s);
206 retval = vsprintf(s + strlen(s), format, ap);
207 strcat(s, "\033[0m");
209 retval = vsprintf(s, format, ap);
215 int pprintf_prompt(int p, char *format,...)
219 va_start(ap, format);
220 retval = vpprintf(p, 1, format, ap);
226 /* send a prompt to p */
227 void send_prompt(int p)
229 struct player *pp = &player_globals.parray[p];
230 const char *prompt = pp->prompt;
233 isspace(prompt[strlen(prompt)-1])?"":" ");
236 int pprintf_noformat(int p, char *format,...)
240 va_start(ap, format);
241 retval = vpprintf(p, 0, format, ap);
248 if (CheckPFlag(p, PFLAG_BELL))
253 int psend_raw_file(int p, char *dir, char *file)
255 struct player *pp = &player_globals.parray[p];
257 char tmp[MAX_LINE_SIZE];
260 fp = fopen_p("%s/%s", "r", dir, file);
264 while ((num = fread(tmp, sizeof(char), MAX_LINE_SIZE - 1, fp)) > 0) {
266 net_send_string(pp->socket, tmp, 1, pp->d_width + 1);
273 send a file a page at a time
275 int psend_file(int p, const char *dir, const char *file)
277 struct player *pp = &player_globals.parray[p];
280 if (strstr(file, "..")) {
281 pprintf(p,"Trying to be tricky, are we?\n");
286 asprintf(&fname,"%s/%s",dir,file);
288 fname = strdup(file);
292 pp->more_text = file_load(fname, NULL);
293 if (!pp->more_text) {
299 return pmore_text(p);
303 * Marsalis added on 8/27/95 so that [next] does not
304 * appear in the logout process for those that have
305 * a short screen height. (Fixed due to complaint
306 * in Bug's messages).
308 int psend_logoutfile(int p, char *dir, char *file)
310 return psend_file(p, dir, file);
314 continue with text from a previous command
316 int pmore_text(int p)
318 struct player *pp = &player_globals.parray[p];
319 int lcount = pp->d_height - 1;
321 if (!pp->more_text) {
322 pprintf(p, "There is no more.\n");
326 while (pp->more_text && lcount--) {
327 char *s = strndup(pp->more_text, strcspn(pp->more_text, "\n")+1);
329 net_send_string(pp->socket, s, 1, pp->d_width + 1);
330 s = strdup(pp->more_text+len);
340 pprintf(p, "Type [next] to see next page.\n");
346 char *stolower(char *str)
352 for (i = 0; str[i]; i++) {
353 if (isupper(str[i])) {
354 str[i] = tolower(str[i]);
360 static int safechar(int c)
362 return (isprint(c) && !strchr(">!&*?/<|`$;", c));
365 int safestring(char *str)
371 for (i = 0; str[i]; i++) {
372 if (!safechar(str[i]))
378 int alphastring(char *str)
384 for (i = 0; str[i]; i++) {
385 if (!isalpha(str[i])) {
392 int printablestring(const char *str)
398 for (i = 0; str[i]; i++) {
399 if ((!isprint(str[i])) && (str[i] != '\t') && (str[i] != '\n'))
405 char *hms_desc(int t)
407 static char tstr[80];
408 int days, hours, mins, secs;
410 days = (t / (60*60*24));
411 hours = ((t % (60*60*24)) / (60*60));
412 mins = (((t % (60*60*24)) % (60*60)) / 60);
413 secs = (((t % (60*60*24)) % (60*60)) % 60);
414 if ((days==0) && (hours==0) && (mins==0)) {
415 sprintf(tstr, "%d sec%s",
416 secs, (secs==1) ? "" : "s");
417 } else if ((days==0) && (hours==0)) {
418 /* sprintf(tstr, "%d min%s, %d sec%s",
419 mins, (mins==1) ? "" : "s",
420 secs, (secs==1) ? "" : "s"); */
421 sprintf(tstr, "%d min%s",
422 mins, (mins==1) ? "" : "s");
423 } else if (days==0) {
424 sprintf(tstr, "%d hr%s, %d min%s, %d "
426 hours, (hours==1) ? "" : "s",
427 mins, (mins==1) ? "" : "s",
428 secs, (secs==1) ? "" : "s");
430 sprintf(tstr, "%d day%s, %d hour%s, %d minute%s "
432 days, (days==1) ? "" : "s",
433 hours, (hours==1) ? "" : "s",
434 mins, (mins==1) ? "" : "s",
435 secs, (secs==1) ? "" : "s");
440 char *hms(int t, int showhour, int showseconds, int spaces)
442 static char tstr[20];
452 sprintf(tstr, "%d : %02d", h, m);
454 sprintf(tstr, "%d:%02d", h, m);
456 sprintf(tstr, "%d", m);
460 sprintf(tmp, " : %02d", s);
462 sprintf(tmp, ":%02d", s);
468 /* This is used only for relative timeing since it reports seconds since
469 * about 5:00pm on Feb 16, 1994
471 unsigned tenth_secs(void)
476 gettimeofday(&tp, &tzp);
477 /* .1 seconds since 1970 almost fills a 32 bit int! So lets subtract off
478 * the time right now */
479 return ((tp.tv_sec - 331939277) * 10L) + (tp.tv_usec / 100000);
482 /* This is to translate tenths-secs time back into 1/1/70 time in full
483 * seconds, because vek didn't read utils.c when he programmed new ratings.
484 1 sec since 1970 fits into a 32 bit int OK.
486 int untenths(unsigned tenths)
488 return (tenths / 10 + 331939277 + 0xffffffff / 10 + 1);
491 char *tenth_str(unsigned t, int spaces)
493 return hms((t + 5) / 10, 0, 1, spaces); /* Round it */
496 #define MAX_TRUNC_SIZE 100
498 /* Warning, if lines in the file are greater than 1024 bytes in length, this
500 /* nasty bug fixed by mann, 3-12-95 */
501 int truncate_file(char *file, int lines)
504 int bptr = 0, trunc = 0, i;
505 char tBuf[MAX_TRUNC_SIZE][MAX_LINE_SIZE];
507 if (lines > MAX_TRUNC_SIZE)
508 lines = MAX_TRUNC_SIZE;
509 fp = fopen_s(file, "r");
513 fgets(tBuf[bptr], MAX_LINE_SIZE, fp);
516 if (tBuf[bptr][strlen(tBuf[bptr]) - 1] != '\n') { /* Line too long */
528 fp = fopen_s(file, "w");
529 for (i = 0; i < lines; i++) {
530 fputs(tBuf[bptr], fp);
541 /* Warning, if lines in the file are greater than 1024 bytes in length, this
543 int lines_file(char *file)
547 char tmp[MAX_LINE_SIZE];
549 fp = fopen_s(file, "r");
553 if (fgets(tmp, MAX_LINE_SIZE, fp))
560 int file_has_pname(char *fname, char *plogin)
562 if (!strcmp(file_wplayer(fname), plogin))
564 if (!strcmp(file_bplayer(fname), plogin))
569 char *file_wplayer(char *fname)
571 static char tmp[MAX_FILENAME_SIZE];
574 ptr = rindex(tmp, '-');
581 char *file_bplayer(char *fname)
585 ptr = rindex(fname, '-');
592 make a human readable IP
594 char *dotQuad(struct in_addr a)
599 int file_exists(char *fname)
603 fp = fopen_s(fname, "r");
610 char *ratstr(int rat)
613 static char tmp[20][10];
618 sprintf(tmp[on], "%4d", rat);
620 sprintf(tmp[on], "----");
627 char *ratstrii(int rat, int p)
630 static char tmp[20][10];
635 sprintf(tmp[on], "%4d", rat);
636 } else if (CheckPFlag(p, PFLAG_REG)) {
637 sprintf(tmp[on], "----");
639 sprintf(tmp[on], "++++");
646 struct t_tree *left, *right;
647 char name; /* Not just 1 char - space for whole name */
648 }; /* is allocated. Maybe a little cheesy? */
651 struct t_dirs *left, *right;
652 time_t mtime; /* dir's modification time */
653 struct t_tree *files;
654 char name; /* ditto */
657 static char **t_buffer = NULL; /* pointer to next space in return buffer */
658 static int t_buffersize = 0; /* size of return buffer */
660 /* fill t_buffer with anything matching "want*" in file tree t_tree */
661 static void t_sft(const char *want, struct t_tree *t)
664 int cmp = strncmp(want, &t->name, strlen(want));
665 if (cmp <= 0) /* if want <= this one, look left */
666 t_sft(want, t->left);
667 if (t_buffersize && (cmp == 0)) { /* if a match, add it to buffer */
669 *t_buffer++ = &(t->name);
671 if (cmp >= 0) /* if want >= this one, look right */
672 t_sft(want, t->right);
676 /* delete file tree t_tree */
677 static void t_cft(struct t_tree **t)
687 /* make file tree for dir d */
688 static void t_mft(struct t_dirs *d)
694 if ((dirp = opendir(&(d->name))) == NULL) {
695 d_printf( "CHESSD:mft() couldn't opendir.\n");
697 while ((dp = readdir(dirp))) {
699 if (dp->d_name[0] != '.') { /* skip anything starting with . */
701 if (strcmp(dp->d_name, &(*t)->name) < 0) {
707 *t = malloc(sizeof(struct t_tree) + strlen(dp->d_name));
708 (*t)->right = (*t)->left = NULL;
709 strcpy(&(*t)->name, dp->d_name);
716 int search_directory(const char *dir, const char *filter, char **buffer, int buffersize)
718 /* dir = directory to search
719 filter = what to search for
720 buffer = where to store pointers to matches
721 buffersize = how many pointers will fit inside buffer */
723 static struct t_dirs *ramdirs = NULL;
726 static char nullify = '\0';
730 t_buffersize = buffersize;
732 if (!stat(dir, &statbuf)) {
733 if (filter == NULL) /* NULL becomes pointer to null string */
736 while (*i) { /* find dir in dir tree */
737 cmp = strcmp(dir, &(*i)->name);
745 if (!*i) { /* if dir isn't in dir tree, add him */
746 *i = malloc(sizeof(struct t_dirs) + strlen(dir));
747 (*i)->left = (*i)->right = NULL;
749 strcpy(&(*i)->name, dir);
751 if ((*i)->files) { /* delete any obsolete file tree */
752 if ((*i)->mtime != statbuf.st_mtime) {
756 if ((*i)->files == NULL) { /* if no file tree for him, make one */
757 (*i)->mtime = statbuf.st_mtime;
760 t_sft(filter, (*i)->files); /* finally, search for matches */
762 return (buffersize - t_buffersize);
765 int display_directory(int p, char **buffer, int count)
766 /* buffer contains 'count' string pointers */
768 struct player *pp = &player_globals.parray[p];
770 multicol *m = multicol_start(count);
772 for (i = 0; (i < count); i++)
773 multicol_store(m, *buffer++);
774 multicol_pprint(m, p, pp->d_width, 1);
779 void CenterText (char *target, const char *text, int width, int pad)
785 left = (width + 1 - len) / 2; /* leading blank space. */
788 asprintf (&format, "%%%ds%%-%ds", left, width-left); /* e.g. "%5s%-10s" */
790 asprintf (&format, "%%%ds%%s", left); /* e.g. "%5s%s" */
791 sprintf (target, format, "", text);
799 void block_signal(int signum)
803 sigaddset(&set,signum);
804 sigprocmask(SIG_BLOCK,&set,NULL);
807 /* unblock a signal */
808 void unblock_signal(int signum)
812 sigaddset(&set,signum);
813 sigprocmask(SIG_UNBLOCK,&set,NULL);
817 int file_copy(const char *src, const char *dest)
822 fd1 = open(src, O_RDONLY);
823 if (fd1 == -1) return -1;
826 fd2 = open(dest, O_WRONLY|O_CREAT|O_EXCL, 0644);
832 while ((n = read(fd1, buf, sizeof(buf))) > 0) {
833 if (write(fd2, buf, n) != n) {
848 int dprintf(int fd, const char *format, ...)
854 va_start(ap, format);
855 vasprintf(&ptr, format, ap);
859 ret = write(fd, ptr, strlen(ptr));
868 #ifndef HAVE_STRNLEN_X
870 some platforms don't have strnlen
872 size_t strnlen(const char *s, size_t n)
875 for (i=0; s[i] && i<n; i++) /* noop */ ;
880 /* day as a string */
881 const char *strday(time_t *t)
883 struct tm *stm = localtime(t);
884 static char tstr[100];
886 strftime(tstr, sizeof(tstr), "%a %b %e", stm);
891 static const char *strtime(struct tm * stm, short gmt)
893 static char tstr[100];
896 strftime(tstr, sizeof(tstr), "%a %b %e, %H:%M GMT %Y", stm);
898 strftime(tstr, sizeof(tstr), "%a %b %e, %H:%M %Z %Y", stm);
902 const char *strltime(time_t *clock)
904 struct tm *stm = localtime(clock);
905 return strtime(stm, 0);
908 const char *strgtime(time_t *clock)
910 struct tm *stm = gmtime(clock);
911 return strtime(stm, 1);
914 /* useful debug utility */
915 void d_printf(const char *fmt, ...)
918 time_t t = time(NULL);
919 fprintf(stderr,"%s ", strltime(&t));
921 vfprintf(stderr,fmt,ap);
926 /* append something to admin.log */
927 static void admin_printf(const char *fmt, ...)
931 time_t t = time(NULL);
933 fd = open("admin.log", O_APPEND | O_CREAT | O_RDWR, 0600);
935 d_printf("Failed to open admin.log - %s\n", strerror(errno));
939 dprintf(fd,"%s ", strltime(&t));
950 void admin_log(struct player *pp, const char *command, param_list params)
956 asprintf(&s, "%s: %s", pp->login, command);
959 for (i=0; params[i].type != TYPE_NULL; i++) {
960 switch (params[i].type) {
962 asprintf(&s2, "%s %d", s, params[i].val.integer);
965 asprintf(&s2, "%s %s", s, params[i].val.string);
968 asprintf(&s2, "%s %s", s, params[i].val.word);
977 admin_printf("%s\n", s);
982 save a lump of data into a file.
985 int file_save(const char *fname, void *data, size_t length)
989 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644);
993 if (write(fd, data, length) != length) {
1003 load a file into memory from a fd.
1005 char *fd_load(int fd, size_t *size)
1010 if (fstat(fd, &sbuf) != 0) return NULL;
1012 p = (char *)malloc(sbuf.st_size+1);
1013 if (!p) return NULL;
1015 if (pread(fd, p, sbuf.st_size, 0) != sbuf.st_size) {
1019 p[sbuf.st_size] = 0;
1021 if (size) *size = sbuf.st_size;
1027 load a file into memory
1029 char *file_load(const char *fname, size_t *size)
1034 if (!fname || !*fname) return NULL;
1036 fd = open(fname,O_RDONLY);
1037 if (fd == -1) return NULL;
1039 p = fd_load(fd, size);
1046 this is like fgets() but operates on a file descriptor
1048 char *fd_gets(char *line, size_t maxsize, int fd)
1052 while (n < (maxsize-1) && read(fd, &c, 1) == 1) {
1054 if (c == '\n') break;
1062 like fopen() but uses printf style arguments for the file name
1064 FILE *fopen_p(const char *fmt, const char *mode, ...)
1070 vasprintf(&s, fmt, ap);
1072 if (!s) return NULL;
1073 if (strstr(s, "..")) {
1074 d_printf("Invalid filename [%s]\n", s);
1084 like fopen() but doesn't allow opening of filenames containing '..'
1086 FILE *fopen_s(const char *fname, const char *mode)
1088 return fopen_p("%s", mode, fname);
1092 #ifndef HAVE_STRLCPY
1094 * Like strncpy but does not 0 fill the buffer and always null
1097 * @param bufsize is the size of the destination buffer.
1099 * @return index of the terminating byte.
1101 size_t strlcpy(char *d, const char *s, size_t bufsize)
1103 size_t len = strlen(s);
1105 if (bufsize <= 0) return 0;
1106 if (len >= bufsize) len = bufsize-1;
1115 set an integer value in a TDB
1117 int tdb_set_int(TDB_CONTEXT *tdb, const char *name, int value)
1122 key.dptr = strdup(name);
1123 key.dsize = strlen(name)+1;
1125 data.dptr = (char *)&value;
1126 data.dsize = sizeof(value);
1128 ret = tdb_store(tdb, key, data, TDB_REPLACE);
1134 get an integer value from a TDB. Return def_value if its not there
1136 int tdb_get_int(TDB_CONTEXT *tdb, const char *name, int def_value)
1141 key.dptr = strdup(name);
1142 key.dsize = strlen(name)+1;
1144 data = tdb_fetch(tdb, key);
1151 ret = *(int *)data.dptr;
1159 set a string value in a TDB
1161 int tdb_set_string(TDB_CONTEXT *tdb, const char *name, const char *value)
1166 key.dptr = strdup(name);
1167 key.dsize = strlen(name)+1;
1169 data.dptr = strdup(value);
1170 data.dsize = strlen(value)+1;
1172 ret = tdb_store(tdb, key, data, TDB_REPLACE);
1179 get a string value from a TDB. Caller frees.
1181 const char *tdb_get_string(TDB_CONTEXT *tdb, const char *name)
1185 key.dptr = strdup(name);
1186 key.dsize = strlen(name)+1;
1188 data = tdb_fetch(tdb, key);
1197 delete a value from a TDB by string
1199 int tdb_delete_string(TDB_CONTEXT *tdb, const char *name)
1204 key.dptr = strdup(name);
1205 key.dsize = strlen(name)+1;
1207 ret = tdb_delete(tdb, key);