From 01ab8df5db7416bcf97c865c50176816c5d8a3a7 Mon Sep 17 00:00:00 2001 From: ac_stef Date: Fri, 19 Jun 2009 12:51:25 +0000 Subject: [PATCH] read motd from file (multilanguage); auto reload changed serverinfo and motd files git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@4527 e016b1c5-ed68-44aa-a2f7-31cac88cffde --- config/motd_en.txt | 14 ++++++++ source/src/client.cpp | 2 ++ source/src/protocol.cpp | 11 +++++++ source/src/protos.h | 10 +++--- source/src/server.cpp | 65 ++++++++++++++++++++++++++++---------- source/src/serveractions.h | 9 +++++- 6 files changed, 88 insertions(+), 23 deletions(-) create mode 100644 config/motd_en.txt diff --git a/config/motd_en.txt b/config/motd_en.txt new file mode 100644 index 00000000..c3ce0ce0 --- /dev/null +++ b/config/motd_en.txt @@ -0,0 +1,14 @@ +// extended serverinfo file +// ======================== +// WARNING: You can NOT use CubeScript in here!! +// +// This text file is read, whenever a the MOTD is sent to a client. +// Comments are removed, also leading and trailing blanks and empty lines. +// +// Don't use more than 80 characters per line. You can use colors and TABs. +// The available colors are: 0: green, 1: blue, 2: yellow, 3: red, 4: gray, 5: white, 6: dark brown, 7: dark red +// +// Example: +// BobsInstagibServer \f3play nicely! +// contact me at a@b.c + diff --git a/source/src/client.cpp b/source/src/client.cpp index a039c29d..9df52822 100644 --- a/source/src/client.cpp +++ b/source/src/client.cpp @@ -420,6 +420,8 @@ void sendintro() 0); sendstring(player1->name, p); sendstring(genpwdhash(player1->name, clientpassword, sessionid), p); + const char *lang = getalias("LANG"); + sendstring(!lang || strlen(lang) != 2 ? "" : lang, p); putint(p, connectrole); clientpassword[0] = '\0'; connectrole = CR_DEFAULT; diff --git a/source/src/protocol.cpp b/source/src/protocol.cpp index 4a50e2d7..69337c63 100644 --- a/source/src/protocol.cpp +++ b/source/src/protocol.cpp @@ -159,6 +159,17 @@ void filterservdesc(char *dst, const char *src, int len) *dst = '\0'; } +void filterlang(char *d, const char *s) +{ + if(strlen(s) == 2) + { + loopi(2) d[i] = tolower(s[i]); + d[2] = '\0'; + if(islower(d[0]) && islower(d[1])) return; + } + *d = '\0'; +} + void cutcolorstring(char *text, int len) { // limit string length, ignore color codes while(*text) diff --git a/source/src/protos.h b/source/src/protos.h index b6b4b388..8c46db12 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -689,6 +689,7 @@ extern void getstring(char *t, ucharbuf &p, int len = MAXTRANS); extern void filtertext(char *dst, const char *src, int whitespace = 1, int len = sizeof(string)-1); extern void filterrichtext(char *dst, const char *src, int len = sizeof(string)-1); extern void filterservdesc(char *dst, const char *src, int len = sizeof(string)-1); +extern void filterlang(char *d, const char *s); extern void cutcolorstring(char *text, int len); extern void startintermission(); extern void restoreserverstate(vector &ents); @@ -727,7 +728,7 @@ extern bool logline(int level, const char *msg, ...); struct servercommandline { int uprate, serverport, syslogfacility, filethres, syslogthres, maxdemos, maxclients, kickthreshold, banthreshold, verbose; - const char *ip, *master, *logident, *serverpassword, *adminpasswd, *demopath, *maprot, *pwdfile, *blfile, *nbfile, *infopath; + const char *ip, *master, *logident, *serverpassword, *adminpasswd, *demopath, *maprot, *pwdfile, *blfile, *nbfile, *infopath, *motdpath; bool demoeverymatch, logtimestamp; string motd, servdesc_full, servdesc_pre, servdesc_suf, voteperm, mapperm; int clfilenesting; @@ -737,7 +738,7 @@ struct servercommandline maxclients(DEFAULTCLIENTS), kickthreshold(-5), banthreshold(-6), verbose(0), ip(""), master(NULL), logident(""), serverpassword(""), adminpasswd(""), demopath(""), maprot("config/maprot.cfg"), pwdfile("config/serverpwd.cfg"), blfile("config/serverblacklist.cfg"), nbfile("config/nicknameblacklist.cfg"), - infopath("config/serverinfo"), + infopath("config/serverinfo"), motdpath("config/motd"), demoeverymatch(true), logtimestamp(false), clfilenesting(0) { @@ -750,7 +751,7 @@ struct servercommandline const char *a = arg + 2 + strspn(arg + 2, " "); int ai = atoi(a); switch(arg[1]) - { // todo: egjlqEGHJOQUYZ + { // todo: egjlqEGHJQUYZ case 'u': uprate = ai; break; case 'f': if(ai > 0 && ai < 65536) serverport = ai; break; case 'i': ip = a; break; @@ -785,6 +786,7 @@ struct servercommandline case 'K': nbfile = a; break; case 'I': infopath = a; break; case 'o': filterrichtext(motd, a); break; + case 'O': motdpath = a; break; case 'n': { char *t = servdesc_full; @@ -800,7 +802,6 @@ struct servercommandline case 'P': s_strcat(voteperm, a); break; case 'M': s_strcat(mapperm, a); break; case 'V': verbose++; break; -#ifdef STANDALONE case 'C': if(*a && clfilenesting < 3) { extern char *loadcfgfile(char *cfg, const char *name, int *len); @@ -825,7 +826,6 @@ struct servercommandline clfilenesting--; break; } -#endif default: return false; } return true; diff --git a/source/src/server.cpp b/source/src/server.cpp index 123c8261..180a4868 100644 --- a/source/src/server.cpp +++ b/source/src/server.cpp @@ -28,6 +28,7 @@ void changeclientrole(int client, int role, char *pwd = NULL, bool force=false); int mapavailable(const char *mapname); void getservermap(void); mapstats *getservermapstats(const char *mapname, bool getlayout = false); +const char *getmotd(const char *lang); int findmappath(const char *mapname, char *filename = NULL); enum { MAP_NOTFOUND = 0, MAP_TEMP, MAP_CUSTOM, MAP_LOCAL, MAP_OFFICIAL }; @@ -244,6 +245,7 @@ struct client // server side version of "dynent" type ENetPeer *peer; string hostname; string name, team; + char lang[3]; int ping; int skin; int vote; @@ -2765,11 +2767,12 @@ void welcomepacket(ucharbuf &p, int n, ENetPacket *packet, bool forcedeath) } putint(p, SV_AUTOTEAM); putint(p, autoteam ? 1 : 0); - if(scl.motd[0]) + const char *motd = scl.motd[0] ? scl.motd : getmotd(c ? c->lang : ""); + if(motd) { - CHECKSPACE(5+2*(int)strlen(scl.motd)+1); + CHECKSPACE(5+2*(int)strlen(motd)+1); putint(p, SV_TEXT); - sendstring(scl.motd, p); + sendstring(motd, p); } #undef CHECKSPACE @@ -2844,6 +2847,8 @@ void process(ENetPacket *packet, int sender, int chan) // sender may be -1 getstring(text, p); s_strcpy(cl->pwd, text); + getstring(text, p); + filterlang(cl->lang, text); int wantrole = getint(p); cl->state.nextprimary = getint(p); bool banned = isbanned(sender); @@ -3795,9 +3800,9 @@ void extping_namelist(ucharbuf &p) #define MAXINFOLINELEN 100 // including color codes -const char *readserverinfo(const char *lang) +char *readserverinfo(const char *fnbase, const char *lang) { - s_sprintfd(fname)("%s_%s.txt", scl.infopath, lang); + s_sprintfd(fname)("%s_%s.txt", fnbase, lang); path(fname); int len, n; char *c, *s, *t, *buf = loadfile(fname, &len); @@ -3815,32 +3820,58 @@ const char *readserverinfo(const char *lang) *t = '\0'; delete[] buf; if(!*nbuf) DELETEA(nbuf); + logline(ACLOG_DEBUG,"read file \"%s\"", fname); return nbuf; } -struct serverinfotext { char lang[3]; const char *info; }; +struct serverinfotext { int type; char lang[3]; char *info; int lastcheck; }; vector serverinfotexts; +enum { SINFO_EXT = 0, SINFO_MOTD, SINFO_NUM }; +const char *sinfo_fns[] = { scl.infopath, scl.motdpath }; -const char *getserverinfo(const char *lang) +const char *getserverinfo(int type, const char *lang) { - if(!islower(lang[0]) || !islower(lang[1])) return NULL; - serverinfotext s; - loopi(3) s.lang[i] = lang[i]; + serverinfotext sn = { type, { 0, 0, 0 }, NULL, 0} , *s = &sn; + filterlang(sn.lang, lang); + if(!sn.lang[0] || type < 0 || type >= SINFO_NUM) return NULL; loopv(serverinfotexts) { - if(!strcmp(s.lang, serverinfotexts[i].lang) && serverinfotexts[i].info) return serverinfotexts[i].info; + serverinfotext &si = serverinfotexts[i]; + if(si.type == s->type && !strcmp(si.lang, s->lang)) + { + if(servmillis - si.lastcheck > (si.info ? 15 : 45) * 60 * 1000) + { // re-read existing files after 15 minutes; search missing again after 45 minutes + DELETEA(si.info); + s = &si; + } + else return si.info; + } } - s.info = readserverinfo(lang); - serverinfotexts.add(s); - return s.info; + s->info = readserverinfo(sinfo_fns[type], lang); + s->lastcheck = servmillis; + if(s == &sn) serverinfotexts.add(*s); + if(s->type == SINFO_MOTD && s->info) + { + char *c = s->info; + while(*c) { c += strlen(c); if(c[1]) *c++ = '\n'; } + if(strlen(s->info) > _MAXDEFSTR) s->info[_MAXDEFSTR] = '\0'; // keep MOTD at sane lengths + } + return s->info; +} + +const char *getmotd(const char *lang) +{ + const char *motd; + if(*lang && (motd = getserverinfo(SINFO_MOTD, lang))) return motd; + return getserverinfo(SINFO_MOTD, "en"); } void extping_serverinfo(ucharbuf &pi, ucharbuf &po) { char lang[3]; lang[0] = tolower(getint(pi)); lang[1] = tolower(getint(pi)); lang[2] = '\0'; - const char *reslang = lang, *buf = getserverinfo(lang); // try client language - if(!buf) buf = getserverinfo(reslang = "en"); // try english + const char *reslang = lang, *buf = getserverinfo(SINFO_EXT, lang); // try client language + if(!buf) buf = getserverinfo(SINFO_EXT, reslang = "en"); // try english sendstring(buf ? reslang : "", po); if(buf) { @@ -4006,7 +4037,7 @@ void initserver(bool dedicated) readpwdfile(scl.pwdfile); readipblacklist(scl.blfile); nbl.readnickblacklist(scl.nbfile); - getserverinfo("en"); // cache 'en' serverinfo + getserverinfo(SINFO_EXT, "en"); // cache 'en' serverinfo if(scl.demoeverymatch) logline(ACLOG_VERBOSE, "recording demo of every game (holding up to %d in memory)", scl.maxdemos); if(scl.demopath[0]) logline(ACLOG_VERBOSE,"all recorded demos will be written to: \"%s\"", scl.demopath); if(scl.voteperm[0]) logline(ACLOG_VERBOSE,"vote permission string: \"%s\"", scl.voteperm); diff --git a/source/src/serveractions.h b/source/src/serveractions.h index 037294bb..5e7da753 100644 --- a/source/src/serveractions.h +++ b/source/src/serveractions.h @@ -79,7 +79,14 @@ struct mapaction : serveraction } loopv(scl.adminonlymaps) { - if(!strcmp(behindpath(map), scl.adminonlymaps[i])) role = CR_ADMIN; + const char *s = scl.adminonlymaps[i], *h = strchr(s, '#'), *m = behindpath(map); + int sl = strlen(s); + if(h && h != s) + { + sl = (int) (h - s); + if(mode != atoi(h + 1)) continue; + } + if(sl == strlen(m) && !strncmp(m, scl.adminonlymaps[i], sl)) role = CR_ADMIN; } } else mapok = true;