#include <map> #include <string> #include <list> #include <cctype> #include <cstdio> #include "musicmud.h" #include "util.h" #include "misc.h" #include "musictok.h" #include "aberchat.h" #include "mailboard.h" #include "zoneload.h" using namespace std; static void notify_mail(const char *who, const char *from) { MudObject *what = planet->get(who); if (what) { what->set_bflag(FL_HASMAIL, 1); what->printf("^YYou have new mail from %s!^n\a\n", from); return; } else { FILE *f = xopen(".", ssprintf(DATA_MAIL"/%s.new", who).c_str(), "w"); if (f) { fprintf(f, ".\n"); fclose(f); } } } static string many_of(string a, int width) { string f = ""; while (width>0) { f += a; width--; } return f; } const char *Message::header(const char *n) const { if (find(n)!=end()) return find(n)->second.c_str(); return 0; } void Message::show(MudObject *who) { int width = columns(who)-1; string rule = many_of("^=", width); string rule2 = many_of("^-", width); who->printf("^B%s^n\n", rule.c_str()); who->printf("From: ^p%s^n\n", header("from")); who->printf("Subject: ^Z%s\n", header("subject")); struct tm tm; strptime(header("date"), "%c", &tm); time_t newtime = mktime(&tm); who->printf("Date: %s\n", ctime_for(who, &newtime)); who->printf("^B%s^n\n", rule2.c_str()); who->printf("%s", data.c_str()); who->printf("^B%s^n\n", rule.c_str()); } const Message *MessageFile::get(int idx) { list<Message>::iterator i = msg.begin(); int count = 1; while (i != msg.end()) { if (count == idx) return &*i; i++; count++; } return 0; } set<int> MessageFile::get_seen(MudObject *who, int min) { set<int> s; if (!who) return s; const char *str = who->get(propname()); if (!str) return s; StrTok t(str); while (const char *a=t.next(",")) { int an = atoi(a), tn = an; char *hyp = strchr(a, '-'); if (hyp) tn = atoi(hyp+1); for (int i=an;i<=tn;i++) if (i >= min) s.insert(i); } return s; } void MessageFile::set_seen(MudObject *who, const set<int> &s) { set<int>::iterator i = s.begin(); string st = ""; int spanfirst = -1; int spanlast = -1; while (i != s.end()) { int thisi = *i; if (spanfirst == -1) { spanfirst = thisi; spanlast = thisi; i++; continue; } if (thisi == (spanlast+1)) { spanlast = thisi; } else { st += ssprintf(spanfirst==spanlast?"%i,":"%i-%i,", spanfirst, spanlast); spanfirst = thisi; spanlast = thisi; } i++; } if (spanlast != -1) st += ssprintf(spanfirst==spanlast?"%i,":"%i-%i,", spanfirst, spanlast); if (st.length()) { st.erase(st.length()-1); who->set(propname(), st.c_str()); } else { who->unset(propname()); } } int MessageFile::count_messages() { return msg.size(); } int MessageFile::count_new(MudObject *who) { set<int> seen = get_seen(who); int news = 0; list<Message>::iterator i = msg.begin(); while (i != msg.end()) { int id = atoi(i->header("id")); if (seen.find(id) == seen.end()) { news++; } i++; } return news; } int MessageFile::index2id(int idx) { list<Message>::iterator i = msg.begin(); int count = 1; while (i != msg.end()) { if (count == idx) return atoi(i->header("id")); i++; count++; } return -1; } int MessageFile::id2index(int id) { list<Message>::iterator i = msg.begin(); int count = 1; while (i != msg.end()) { int thisid = atoi(i->header("id")); if (thisid == id) return count; i++; count++; } return -1; } void MessageFile::list_contents(MudObject *who, const char *cmd, set<int> *td) { int count = 1; set<int> seen = get_seen(who); list<Message>::iterator i = msg.begin(); while (i != msg.end()) { const char *m = " "; int id = atoi(i->header("id")); if (seen.find(id) == seen.end()) { m = "^Y*^n"; } if (td && td->find(id) != td->end()) { m = "^RD^n"; } string link = ssprintf("\3send href='%s%i'\4%i^n\3/send\4", cmd, count, count); who->printf(" %s ^G%3s ^p%-14s^n ^Z%s\n", m, link.c_str(), i->header("from"), i->header("subject")); count++; i++; } } bool MessageFile::show_message(MudObject *who, int which) { /// XXX : implement "read first new" as which==-1 list<Message>::iterator i = msg.begin(); set<int> seen = get_seen(who); int count = 1; while (i != msg.end()) { if (count == which) { i->show(who); seen.insert(atoi(i->header("id"))); set_seen(who, seen); return 1; } i++; count++; } return 0; } void MessageFile::send_message(const char *name, const char *owner, const char *subject, const char *date, const char *data) { Message m; m.data = data; m["from"] = name; m["owner"] = owner; m["subject"] = subject; string dat = date; if (dat.find('\n')!=string::npos) { dat = dat.substr(0, dat.find('\n')); date = dat.c_str(); } m["date"] = date; maxid++; m["id"] = ssprintf("%i", maxid); msg.push_back(m); output(); } const char *MessageFile::get_header(int which, const char *b) { list<Message>::iterator i = msg.begin(); int count = 1; while (i != msg.end()) { if (count == which) { return i->header(b); } i++; count++; } return 0; } void MessageFile::delete_message(int id) { list<Message>::iterator i = msg.begin(); int count = 1; while (i != msg.end()) { if (count == id) { msg.erase(i); output(); return; } i++; count++; } } void MessageFile::output() { FILE *f = xopen(m_dir.c_str(), (m_file+".tmp").c_str(), "w"); if (!f) return; fprintf(f, "%06i\n\n", maxid); list<Message>::iterator i = msg.begin(); while (i != msg.end()) { Message a = *i; fprintf(f, "__POST\n"); fprintf(f, "From: %s\n", a["from"].c_str()); fprintf(f, "Owner: %s\n", a["owner"].c_str()); fprintf(f, "Subject: %s\n", a["subject"].c_str()); fprintf(f, "Date: %s\n", a["date"].c_str()); fprintf(f, "ID: %s\n", a["id"].c_str()); a.erase("from"); a.erase("owner"); a.erase("subject"); a.erase("date"); a.erase("id"); fprintf(f, "\n"); fprintf(f, "%s", a.data.c_str()); i++; } fclose(f); rename((m_dir+"/"+m_file+".tmp").c_str(), (m_dir+"/"+m_file).c_str()); } MessageFile::MessageFile(const char *dir, const char *file) : maxid(0) { this->prop = "seen-"; if (strstr(dir, "news")) { this->prop += "news-"; this->prop += file; } if (strstr(dir, "mail")) this->prop += "mail"; m_dir = dir; m_file = file; FILE *f = xopen(dir, file, "r"); if (!f) { maxid = 0; return; } maxid = atoi(getline(f).c_str()); while (getline(f) != ""); while (1) { string s = getline(f); if (feof(f)) break; eep: if (s == "__POST") { Message m; while (1) { s = getline(f); if (feof(f)) break; string field = s.substr(0, s.find(':')); for (size_t i=0;i<field.length();i++) { field[i] = tolower(field[i]); } if (s == "") break; m[field] = s.substr(s.find(':')+2); } string data; while (1) { string tl = getline(f); if (feof(f)) { break; } if (tl == "__POST") { s = tl; m.data = data; msg.push_back(m); goto eep; } data += tl; data += "\n"; } m.data = data; msg.push_back(m); } } xclose(f); } const char *sendmail(const char *to, const char *from, const char *subj, const char *date, const char *data) { if (strlen(to)>100) return 0; if (strchr(to, '.')) return 0; if (strchr(to, '/')) return 0; string t = to; for (size_t i=0;i<t.length();i++) t[i] = tolower(t[i]); if (strchr(to, '@')) { string tomud = t.substr(t.find('@')+1); string touse = t.substr(0, t.find('@')); if (abermail_hook) { abermail_hook(from, touse.c_str(), tomud.c_str(), subj, date, data); return 0; } return "oops"; } MessageFile f(DATA_MAIL, to); time_t when = (time_t)atoi(date); if (!when) when = now; f.send_message(from, from, subj, ctime(&when), data); notify_mail(to, from); return 0; }