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 static int recurse = 0;
91 struct player *pp = &player_globals.parray[p];
94 int current_socket = pp->socket;
97 if(recurse > 10) return COM_BADPARAMETERS; /* [HGM] guard against infinite recursion through bad aliasing */
100 vasprintf(&tmp, comstr, ap);
103 retval = process_input(current_socket, tmp);
106 if (retval == COM_LOGOUT) {
107 process_disconnection(current_socket);
108 net_close_connection(current_socket);
113 static int vpprintf(int p, int do_formatting, char *format,va_list ap)
115 struct player *pp = &player_globals.parray[p];
119 retval = vasprintf(&tmp, format, ap);
121 net_send_string(pp->socket,
133 int pprintf(int p, char *format,...)
137 va_start(ap, format);
138 retval = vpprintf(p, 1, format, ap);
143 static void pprintf_dohightlight(int p)
145 struct player *pp = &player_globals.parray[p];
146 if (pp->highlight & 0x01)
147 pprintf(p, "\033[7m");
148 if (pp->highlight & 0x02)
149 pprintf(p, "\033[1m");
150 if (pp->highlight & 0x04)
151 pprintf(p, "\033[4m");
152 if (pp->highlight & 0x08)
153 pprintf(p, "\033[2m");
156 int pprintf_highlight(int p, char *format,...)
158 struct player *pp = &player_globals.parray[p];
162 pprintf_dohightlight(p);
163 va_start(ap, format);
164 retval = vpprintf(p, 1, format, ap);
167 pprintf(p, "\033[0m");
171 static void sprintf_dohightlight(int p, char *s)
173 struct player *pp = &player_globals.parray[p];
174 if (pp->highlight & 0x01)
175 strcat(s, "\033[7m");
176 if (pp->highlight & 0x02)
177 strcat(s, "\033[1m");
178 if (pp->highlight & 0x04)
179 strcat(s, "\033[4m");
180 if (pp->highlight & 0x08)
181 strcat(s, "\033[2m");
185 like pprintf() but with paging for long messages
187 int pprintf_more(int p, char *format,...)
189 struct player *pp = &player_globals.parray[p];
192 va_start(ap, format);
193 vasprintf(&s, format, ap);
199 return pmore_text(p);
202 int psprintf_highlight(int p, char *s, char *format,...)
204 struct player *pp = &player_globals.parray[p];
208 va_start(ap, format);
210 sprintf_dohightlight(p, s);
211 retval = vsprintf(s + strlen(s), format, ap);
212 strcat(s, "\033[0m");
214 retval = vsprintf(s, format, ap);
220 int pprintf_prompt(int p, char *format,...)
224 va_start(ap, format);
225 retval = vpprintf(p, 1, format, ap);
231 /* send a prompt to p */
232 void send_prompt(int p)
234 struct player *pp = &player_globals.parray[p];
235 const char *prompt = pp->prompt;
238 isspace(prompt[strlen(prompt)-1])?"":" ");
241 int pprintf_noformat(int p, char *format,...)
245 va_start(ap, format);
246 retval = vpprintf(p, 0, format, ap);
253 if (CheckPFlag(p, PFLAG_BELL))
258 int psend_raw_file(int p, char *dir, char *file)
260 struct player *pp = &player_globals.parray[p];
262 char tmp[MAX_LINE_SIZE];
265 fp = fopen_p("%s/%s", "r", dir, file);
269 while ((num = fread(tmp, sizeof(char), MAX_LINE_SIZE - 1, fp)) > 0) {
271 net_send_string(pp->socket, tmp, 1, pp->d_width + 1);
278 send a file a page at a time
280 int psend_file(int p, const char *dir, const char *file)
282 struct player *pp = &player_globals.parray[p];
285 if (strstr(file, "..")) {
286 pprintf(p,"Trying to be tricky, are we?\n");
291 asprintf(&fname,"%s/%s",dir,file);
293 fname = strdup(file);
297 pp->more_text = file_load(fname, NULL);
298 if (!pp->more_text) {
304 return pmore_text(p);
308 * Marsalis added on 8/27/95 so that [next] does not
309 * appear in the logout process for those that have
310 * a short screen height. (Fixed due to complaint
311 * in Bug's messages).
313 int psend_logoutfile(int p, char *dir, char *file)
315 return psend_file(p, dir, file);
319 continue with text from a previous command
321 int pmore_text(int p)
323 struct player *pp = &player_globals.parray[p];
324 int lcount = pp->d_height - 1;
326 if (!pp->more_text) {
327 pprintf(p, "There is no more.\n");
331 while (pp->more_text && lcount--) {
332 char *s = strndup(pp->more_text, strcspn(pp->more_text, "\n")+1);
334 net_send_string(pp->socket, s, 1, pp->d_width + 1);
335 s = strdup(pp->more_text+len);
345 pprintf(p, "Type [next] to see next page.\n");
351 char *stolower(char *str)
357 for (i = 0; str[i]; i++) {
358 if (isupper(str[i])) {
359 str[i] = tolower(str[i]);
365 static int safechar(int c)
367 return (isprint(c) && !strchr(">!&*?/<|`$;", c));
370 int safestring(char *str)
376 for (i = 0; str[i]; i++) {
377 if (!safechar(str[i]))
383 int alphastring(char *str)
389 for (i = 0; str[i]; i++) {
390 if (!isalpha(str[i])) {
397 int printablestring(const char *str)
403 for (i = 0; str[i]; i++) {
404 if ((!isprint(str[i])) && (str[i] != '\t') && (str[i] != '\n'))
410 char *hms_desc(int t)
412 static char tstr[80];
413 int days, hours, mins, secs;
415 days = (t / (60*60*24));
416 hours = ((t % (60*60*24)) / (60*60));
417 mins = (((t % (60*60*24)) % (60*60)) / 60);
418 secs = (((t % (60*60*24)) % (60*60)) % 60);
419 if ((days==0) && (hours==0) && (mins==0)) {
420 sprintf(tstr, "%d sec%s",
421 secs, (secs==1) ? "" : "s");
422 } else if ((days==0) && (hours==0)) {
423 /* sprintf(tstr, "%d min%s, %d sec%s",
424 mins, (mins==1) ? "" : "s",
425 secs, (secs==1) ? "" : "s"); */
426 sprintf(tstr, "%d min%s",
427 mins, (mins==1) ? "" : "s");
428 } else if (days==0) {
429 sprintf(tstr, "%d hr%s, %d min%s, %d "
431 hours, (hours==1) ? "" : "s",
432 mins, (mins==1) ? "" : "s",
433 secs, (secs==1) ? "" : "s");
435 sprintf(tstr, "%d day%s, %d hour%s, %d minute%s "
437 days, (days==1) ? "" : "s",
438 hours, (hours==1) ? "" : "s",
439 mins, (mins==1) ? "" : "s",
440 secs, (secs==1) ? "" : "s");
445 char *hms(int t, int showhour, int showseconds, int spaces)
447 static char tstr[20];
457 sprintf(tstr, "%d : %02d", h, m);
459 sprintf(tstr, "%d:%02d", h, m);
461 sprintf(tstr, "%d", m);
465 sprintf(tmp, " : %02d", s);
467 sprintf(tmp, ":%02d", s);
473 /* This is used only for relative timeing since it reports seconds since
474 * about 5:00pm on Feb 16, 1994
476 unsigned tenth_secs(void)
481 gettimeofday(&tp, &tzp);
482 /* .1 seconds since 1970 almost fills a 32 bit int! So lets subtract off
483 * the time right now */
484 return ((tp.tv_sec - 331939277) * 10L) + (tp.tv_usec / 100000);
487 /* This is to translate tenths-secs time back into 1/1/70 time in full
488 * seconds, because vek didn't read utils.c when he programmed new ratings.
489 1 sec since 1970 fits into a 32 bit int OK.
491 int untenths(unsigned tenths)
493 return (tenths / 10 + 331939277 + 4*((1<<30) / 5) + 1);
496 char *tenth_str(unsigned t, int spaces)
498 return hms((t + 5) / 10, 0, 1, spaces); /* Round it */
501 #define MAX_TRUNC_SIZE 100
503 /* Warning, if lines in the file are greater than 1024 bytes in length, this
505 /* nasty bug fixed by mann, 3-12-95 */
506 int truncate_file(char *file, int lines)
509 int bptr = 0, trunc = 0, i;
510 char tBuf[MAX_TRUNC_SIZE][MAX_LINE_SIZE];
512 if (lines > MAX_TRUNC_SIZE)
513 lines = MAX_TRUNC_SIZE;
514 fp = fopen_s(file, "r");
518 fgets(tBuf[bptr], MAX_LINE_SIZE, fp);
521 if (tBuf[bptr][strlen(tBuf[bptr]) - 1] != '\n') { /* Line too long */
533 fp = fopen_s(file, "w");
534 for (i = 0; i < lines; i++) {
535 fputs(tBuf[bptr], fp);
546 /* Warning, if lines in the file are greater than 1024 bytes in length, this
548 int lines_file(char *file)
552 char tmp[MAX_LINE_SIZE];
554 fp = fopen_s(file, "r");
558 if (fgets(tmp, MAX_LINE_SIZE, fp))
565 int file_has_pname(char *fname, char *plogin)
567 if (!strcmp(file_wplayer(fname), plogin))
569 if (!strcmp(file_bplayer(fname), plogin))
574 char *file_wplayer(char *fname)
576 static char tmp[MAX_FILENAME_SIZE];
579 ptr = rindex(tmp, '-');
586 char *file_bplayer(char *fname)
590 ptr = rindex(fname, '-');
597 make a human readable IP
599 char *dotQuad(struct in_addr a)
604 int file_exists(char *fname)
608 fp = fopen_s(fname, "r");
615 char *ratstr(int rat)
618 static char tmp[20][10];
623 sprintf(tmp[on], "%4d", rat);
625 sprintf(tmp[on], "----");
632 char *ratstrii(int rat, int p)
635 static char tmp[20][10];
640 sprintf(tmp[on], "%4d", rat);
641 } else if (CheckPFlag(p, PFLAG_REG)) {
642 sprintf(tmp[on], "----");
644 sprintf(tmp[on], "++++");
653 struct t_tree *left, *right;
654 char name[OVERRUN+1]; // [HGM] hack below caused crashing on some compilers
655 // char name; /* Not just 1 char - space for whole name */
656 }; /* is allocated. Maybe a little cheesy? */
659 struct t_dirs *left, *right;
660 time_t mtime; /* dir's modification time */
661 struct t_tree *files;
662 char name[OVERRUN+1]; // [HGM] ditto
663 // char name; /* ditto */
666 static char **t_buffer = NULL; /* pointer to next space in return buffer */
667 static int t_buffersize = 0; /* size of return buffer */
669 /* fill t_buffer with anything matching "want*" in file tree t_tree */
670 static void t_sft(const char *want, struct t_tree *t)
673 int cmp = strncmp(want, &t->name, strlen(want));
674 if (cmp <= 0) /* if want <= this one, look left */
675 t_sft(want, t->left);
676 if (t_buffersize && (cmp == 0)) { /* if a match, add it to buffer */
678 *t_buffer++ = &(t->name);
680 if (cmp >= 0) /* if want >= this one, look right */
681 t_sft(want, t->right);
685 /* delete file tree t_tree */
686 static void t_cft(struct t_tree **t)
696 /* make file tree for dir d */
697 static void t_mft(struct t_dirs *d)
703 if ((dirp = opendir(&(d->name))) == NULL) {
704 d_printf( "CHESSD:mft() couldn't opendir.\n");
706 while ((dp = readdir(dirp))) {
708 if (dp->d_name[0] != '.') { /* skip anything starting with . */
710 if (strcmp(dp->d_name, &(*t)->name) < 0) {
716 *t = malloc(sizeof(struct t_tree) - OVERRUN + strlen(dp->d_name));
717 (*t)->right = (*t)->left = NULL;
718 strcpy(&(*t)->name, dp->d_name);
725 int search_directory(const char *dir, const char *filter, char **buffer, int buffersize)
727 /* dir = directory to search
728 filter = what to search for
729 buffer = where to store pointers to matches
730 buffersize = how many pointers will fit inside buffer */
732 static struct t_dirs *ramdirs = NULL;
735 static char nullify = '\0';
739 t_buffersize = buffersize;
741 if (!stat(dir, &statbuf)) {
742 if (filter == NULL) /* NULL becomes pointer to null string */
745 while (*i) { /* find dir in dir tree */
746 cmp = strcmp(dir, &(*i)->name);
754 if (!*i) { /* if dir isn't in dir tree, add him */
755 *i = malloc(sizeof(struct t_dirs) - OVERRUN + strlen(dir)); // [HGM] allocate just enough, even though struct promoised more
756 (*i)->left = (*i)->right = NULL;
758 strcpy(&(*i)->name, dir);
760 if ((*i)->files) { /* delete any obsolete file tree */
761 if ((*i)->mtime != statbuf.st_mtime) {
765 if ((*i)->files == NULL) { /* if no file tree for him, make one */
766 (*i)->mtime = statbuf.st_mtime;
769 t_sft(filter, (*i)->files); /* finally, search for matches */
771 return (buffersize - t_buffersize);
774 int display_directory(int p, char **buffer, int count)
775 /* buffer contains 'count' string pointers */
777 struct player *pp = &player_globals.parray[p];
779 multicol *m = multicol_start(count);
781 for (i = 0; (i < count); i++)
782 multicol_store(m, *buffer++);
783 multicol_pprint(m, p, pp->d_width, 1);
788 void CenterText (char *target, const char *text, int width, int pad)
794 left = (width + 1 - len) / 2; /* leading blank space. */
797 asprintf (&format, "%%%ds%%-%ds", left, width-left); /* e.g. "%5s%-10s" */
799 asprintf (&format, "%%%ds%%s", left); /* e.g. "%5s%s" */
800 sprintf (target, format, "", text);
808 void block_signal(int signum)
812 sigaddset(&set,signum);
813 sigprocmask(SIG_BLOCK,&set,NULL);
816 /* unblock a signal */
817 void unblock_signal(int signum)
821 sigaddset(&set,signum);
822 sigprocmask(SIG_UNBLOCK,&set,NULL);
826 int file_copy(const char *src, const char *dest)
831 fd1 = open(src, O_RDONLY);
832 if (fd1 == -1) return -1;
835 fd2 = open(dest, O_WRONLY|O_CREAT|O_EXCL, 0644);
841 while ((n = read(fd1, buf, sizeof(buf))) > 0) {
842 if (write(fd2, buf, n) != n) {
857 int dprintf(int fd, const char *format, ...)
863 va_start(ap, format);
864 vasprintf(&ptr, format, ap);
868 ret = write(fd, ptr, strlen(ptr));
877 #ifndef HAVE_STRNLEN_X
879 some platforms don't have strnlen
881 size_t strnlen(const char *s, size_t n)
884 for (i=0; s[i] && i<n; i++) /* noop */ ;
889 /* day as a string */
890 const char *strday(time_t *t)
892 struct tm *stm = localtime(t);
893 static char tstr[100];
895 strftime(tstr, sizeof(tstr), "%a %b %e", stm);
900 static const char *strtime(struct tm * stm, short gmt)
902 static char tstr[100];
905 strftime(tstr, sizeof(tstr), "%a %b %e, %H:%M GMT %Y", stm);
907 strftime(tstr, sizeof(tstr), "%a %b %e, %H:%M %Z %Y", stm);
911 const char *strltime(time_t *clock)
913 struct tm *stm = localtime(clock);
914 return strtime(stm, 0);
917 const char *strgtime(time_t *clock)
919 struct tm *stm = gmtime(clock);
920 return strtime(stm, 1);
923 /* useful debug utility */
924 void d_printf(const char *fmt, ...)
927 time_t t = time(NULL);
928 fprintf(stderr,"%s ", strltime(&t));
930 vfprintf(stderr,fmt,ap);
935 /* append something to admin.log */
936 static void admin_printf(const char *fmt, ...)
940 time_t t = time(NULL);
942 fd = open("admin.log", O_APPEND | O_CREAT | O_RDWR, 0600);
944 d_printf("Failed to open admin.log - %s\n", strerror(errno));
948 dprintf(fd,"%s ", strltime(&t));
959 void admin_log(struct player *pp, const char *command, param_list params)
965 asprintf(&s, "%s: %s", pp->login, command);
968 for (i=0; params[i].type != TYPE_NULL; i++) {
969 switch (params[i].type) {
971 asprintf(&s2, "%s %d", s, params[i].val.integer);
974 asprintf(&s2, "%s %s", s, params[i].val.string);
977 asprintf(&s2, "%s %s", s, params[i].val.word);
986 admin_printf("%s\n", s);
991 save a lump of data into a file.
994 int file_save(const char *fname, void *data, size_t length)
998 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644);
1002 if (write(fd, data, length) != length) {
1012 load a file into memory from a fd.
1014 char *fd_load(int fd, size_t *size)
1019 if (fstat(fd, &sbuf) != 0) return NULL;
1021 p = (char *)malloc(sbuf.st_size+1);
1022 if (!p) return NULL;
1024 if (pread(fd, p, sbuf.st_size, 0) != sbuf.st_size) {
1028 p[sbuf.st_size] = 0;
1030 if (size) *size = sbuf.st_size;
1036 load a file into memory
1038 char *file_load(const char *fname, size_t *size)
1043 if (!fname || !*fname) return NULL;
1045 fd = open(fname,O_RDONLY);
1046 if (fd == -1) return NULL;
1048 p = fd_load(fd, size);
1055 this is like fgets() but operates on a file descriptor
1057 char *fd_gets(char *line, size_t maxsize, int fd)
1061 while (n < (maxsize-1) && read(fd, &c, 1) == 1) {
1063 if (c == '\n') break;
1071 like fopen() but uses printf style arguments for the file name
1073 FILE *fopen_p(const char *fmt, const char *mode, ...)
1079 vasprintf(&s, fmt, ap);
1081 if (!s) return NULL;
1082 if (strstr(s, "..")) {
1083 d_printf("Invalid filename [%s]\n", s);
1093 like fopen() but doesn't allow opening of filenames containing '..'
1095 FILE *fopen_s(const char *fname, const char *mode)
1097 return fopen_p("%s", mode, fname);
1101 #ifndef HAVE_STRLCPY
1103 * Like strncpy but does not 0 fill the buffer and always null
1106 * @param bufsize is the size of the destination buffer.
1108 * @return index of the terminating byte.
1110 size_t strlcpy(char *d, const char *s, size_t bufsize)
1112 size_t len = strlen(s);
1114 if (bufsize <= 0) return 0;
1115 if (len >= bufsize) len = bufsize-1;
1124 set an integer value in a TDB
1126 int tdb_set_int(TDB_CONTEXT *tdb, const char *name, int value)
1131 key.dptr = strdup(name);
1132 key.dsize = strlen(name)+1;
1134 data.dptr = (char *)&value;
1135 data.dsize = sizeof(value);
1137 ret = tdb_store(tdb, key, data, TDB_REPLACE);
1143 get an integer value from a TDB. Return def_value if its not there
1145 int tdb_get_int(TDB_CONTEXT *tdb, const char *name, int def_value)
1150 key.dptr = strdup(name);
1151 key.dsize = strlen(name)+1;
1153 data = tdb_fetch(tdb, key);
1160 ret = *(int *)data.dptr;
1168 set a string value in a TDB
1170 int tdb_set_string(TDB_CONTEXT *tdb, const char *name, const char *value)
1175 key.dptr = strdup(name);
1176 key.dsize = strlen(name)+1;
1178 data.dptr = strdup(value);
1179 data.dsize = strlen(value)+1;
1181 ret = tdb_store(tdb, key, data, TDB_REPLACE);
1188 get a string value from a TDB. Caller frees.
1190 const char *tdb_get_string(TDB_CONTEXT *tdb, const char *name)
1194 key.dptr = strdup(name);
1195 key.dsize = strlen(name)+1;
1197 data = tdb_fetch(tdb, key);
1206 delete a value from a TDB by string
1208 int tdb_delete_string(TDB_CONTEXT *tdb, const char *name)
1213 key.dptr = strdup(name);
1214 key.dsize = strlen(name)+1;
1216 ret = tdb_delete(tdb, key);