/*
* post.cpp
* Handles in-game post office.
* ____ _
* | _ \ ___ __ _| |_ __ ___ ___
* | |_) / _ \/ _` | | '_ ` _ \/ __|
* | _ < __/ (_| | | | | | | \__ \
* |_| \_\___|\__,_|_|_| |_| |_|___/
*
* Permission to use, modify and distribute is granted via the
* Creative Commons - Attribution - Non Commercial - Share Alike 3.0 License
* http://creativecommons.org/licenses/by-nc-sa/3.0/
*
* Copyright (C) 2007-2009 Jason Mitchell, Randi Mitchell
* Contributions by Tim Callahan, Jonathan Hseu
* Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman
*
*/
#include "mud.h"
#include "commands.h"
#include "login.h"
void Player::hasNewMudmail() const {
char str[50];
sprintf(str, "%s/%s.txt", POSTPATH, name);
if(file_exists(str) && flagIsSet(P_UNREAD_MAIL))
print("\n*** You have new mudmail in the post office.\n");
}
//*********************************************************************
// canPost
//*********************************************************************
bool canPost(Player* player) {
if(!player->isStaff()) {
if(!player->getRoom()->flagIsSet(R_POST_OFFICE)) {
player->print("This is not a post office.\n");
return(false);
}
}
return(true);
}
//*********************************************************************
// postText
//*********************************************************************
// format text for writing to file
bstring postText(char* str) {
bstring outstr = "";
if(Pueblo::is(str))
outstr = " ";
outstr += str;
outstr = outstr.left(158);
outstr += "\n";
return(outstr);
}
//*********************************************************************
// cmdSendmail
//*********************************************************************
// This function allows a player to send a letter to another player if
// he/she is in a post office.
int cmdSendMail(Player* player, cmd* cmnd) {
Player *target=0;
char file[80];
bool online=false;
if(!canPost(player))
return(0);
if(cmnd->num < 2) {
player->print("Mail whom?\n");
return(0);
}
if(!checkWinFilename(player->getSock(), cmnd->str[1]))
return(0);
cmnd->str[1][0] = up(cmnd->str[1][0]);
if(!Player::exists(cmnd->str[1])) {
player->print("That player does not exist.\n");
return(0);
}
target = gServer->findPlayer(cmnd->str[1]);
if(!target) {
if(!loadPlayer(cmnd->str[1], &target)) {
//player->print("Player does not exist.\n");
return(0);
}
} else
online = true;
if(!target->isStaff() && player->getClass() == BUILDER) {
player->print("You may not mudmail players at this time.\n");
if(!online)
free_crt(target);
return(0);
}
if(!player->isStaff() && target->getClass() == BUILDER) {
player->print("You may not mudmail that character at this time.\n");
if(!online)
free_crt(target);
return(0);
}
if(target->isCt() && !player->isWatcher() && !player->isStaff() && !player->flagIsSet(P_CAN_MUDMAIL_STAFF)) {
player->print("Please do not mudmail Caretakers and DMs directly.\n");
player->print("You need to contact a watcher.\n");
if(!online)
free_crt(target);
return(0);
}
if(!player->isDm() && !target->isDm())
broadcast(isDm, "^g### %s is sending mudmail to %s.", player->name, target->name);
target->setFlag(P_UNREAD_MAIL);
target->save(online);
if(!online)
free_crt(target);
player->print("Enter your message now. Type '.' or '*' on a line by itself to finish or '\\' to\ncancel. Each line should be NO LONGER THAN 80 CHARACTERS.\n-: ");
sprintf(player->getSock()->tempstr[0], "%s", cmnd->str[1]);
sprintf(file, "%s/%s_to_%s.txt", POSTPATH, player->name, player->getSock()->tempstr[0]);
unlink(file);
player->setFlag(P_READING_FILE);
gServer->processOutput();
player->getSock()->setState(CON_SENDING_MAIL);
player->getSock()->intrpt &= ~1;
// player->getSock()->fn = postedit;
// player->getSock()->fnparam = 1;
if(online) {
if(target != player && !target->flagIsSet(P_NO_SHOW_MAIL) && ((!player->isStaff()) ||
(player->isCt() && (!strcmp(cmnd->str[2], "-s") || target->isStaff())))) {
target->printColor("^c### You are receiving new mudmail from %s.\n", player->name);
}
}
return(DOPROMPT);
}
//*********************************************************************
// postedit
//*********************************************************************
// This function is called when a player is editing a message to send
// to another player.
void postedit(Socket* sock, char *str) {
char outcstr[158], datestr[40], filename[80], postfile[80];
long t=0;
int ff=0;
FILE *fp=0;
bstring outstr = "";
Player* ply = sock->getPlayer();
// use a temp file while we're editting it
checkDirExists(POSTPATH, true);
sprintf(filename, "%s/%s_to_%s.txt", POSTPATH, ply->name, sock->tempstr[0]);
if((str[0] == '.' || str[0] == '*') && !str[1]) {
// time to copy the temp file to the real file!
fp = fopen(filename, "r");
// BUGFIX: Make sure fp is valid!!!!
if(!fp) {
ply->clearFlag(P_READING_FILE);
sock->print("Error sending mail.\n");
sock->restoreState();
return;
}
sprintf(postfile, "%s/%s.txt", POSTPATH, sock->tempstr[0]);
ff = open(postfile, O_CREAT | O_APPEND | O_RDWR, ACC);
if(ff < 0)
merror("postedit", FATAL);
time(&t);
strcpy(datestr, (char *) ctime(&t));
datestr[strlen(datestr) - 1] = 0;
sprintf(outcstr, "\n--..__..--..__..--..__..--..__..--..__..--..__..--..__..--..__..--..__..--\n\nMail from %s (%s):\n\n",
ply->name, datestr);
write(ff, outcstr, strlen(outcstr));
while(!feof(fp)) {
fgets(outcstr, sizeof(outcstr), fp);
write(ff, outcstr, strlen(outcstr));
strcpy(outcstr, "");
}
close(ff);
fclose(fp);
unlink(filename);
ply->clearFlag(P_READING_FILE);
sock->print("Mail sent.\n");
sock->restoreState();
return;
}
if(str[0] == '\\' && !str[1]) {
unlink(filename);
ply->clearFlag(P_READING_FILE);
sock->print("Mail cancelled.\n");
sock->restoreState();
return;
}
ff = open(filename, O_CREAT | O_APPEND | O_RDWR, ACC);
if(ff < 0)
merror("postedit", FATAL);
outstr = postText(str);
write(ff, outstr.c_str(), outstr.getLength());
close(ff);
sock->print("-: ");
gServer->processOutput();
sock->intrpt &= ~1;
}
//*********************************************************************
// cmdReadMail
//*********************************************************************
// This function allows a player to read their mail.
int cmdReadMail(Player* player, cmd* cmnd) {
char filename[80];
if(!canPost(player))
return(0);
player->clearFlag(P_UNREAD_MAIL);
sprintf(filename, "%s/%s.txt", POSTPATH, player->name);
if(open(filename, O_RDONLY, 0) < 0) {
player->print("You have no mail.\n");
return(0);
}
viewFile(player->getSock(), filename);
return(DOPROMPT);
}
//*********************************************************************
// dmReadmail
//*********************************************************************
// This function allows a DM to read other peoples' mudmail.
int dmReadmail(Player* player, cmd* cmnd) {
char filename[80];
if(!checkWinFilename(player->getSock(), cmnd->str[1]))
return(0);
cmnd->str[1][0] = up(cmnd->str[1][0]);
if(!Player::exists(cmnd->str[1])) {
player->print("That player does not exist.\n");
return(0);
}
sprintf(filename, "%s/%s.txt", POSTPATH, cmnd->str[1]);
if(!file_exists(filename)) {
player->print("%s currently has no mudmail.\n", cmnd->str[1]);
return(PROMPT);
}
player->print("%s's current mudmail:\n", cmnd->str[1]);
viewFile(player->getSock(), filename);
return(DOPROMPT);
}
//*********************************************************************
// cmdDeleteMail
//*********************************************************************
// This function allows a player to delete their mail.
int cmdDeleteMail(Player* player, cmd* cmnd) {
char file[80];
if(!canPost(player))
return(0);
sprintf(file, "%s/%s.txt", POSTPATH, player->name);
unlink(file);
player->print("Mail deleted.\n");
player->clearFlag(P_UNREAD_MAIL);
return(0);
}
//*********************************************************************
// dmDeletemail
//*********************************************************************
// This function allows a DM to delete a player's mail file.
int dmDeletemail(Player* player, cmd* cmnd) {
Player *creature=0;
char str[50];
cmnd->str[1][0] = up(cmnd->str[1][0]);
if(!Player::exists(cmnd->str[1])) {
player->print("That player does not exist.\n");
return(0);
}
sprintf(str, "%s/%s.txt", POSTPATH, cmnd->str[1]);
if(!file_exists(str)) {
player->print("%s has no mail file to delete.\n", cmnd->str[1]);
return(PROMPT);
}
unlink(str);
player->print("%s's mail deleted.\n", cmnd->str[1]);
creature = gServer->findPlayer(cmnd->str[1]);
if(!creature) {
if(!loadPlayer(cmnd->str[1], &creature)) {
//player->print("Player does not exist.\n");
return(0);
} else {
creature->clearFlag(P_UNREAD_MAIL);
creature->save();
free_crt(creature);
}
} else {
creature->clearFlag(P_UNREAD_MAIL);
creature->save(true);
}
return(0);
}
//*********************************************************************
// notepad
//*********************************************************************
int notepad(Player* player, cmd* cmnd) {
char file[80];
if(cmnd->num == 3 && 0 == strcmp(cmnd->str[2], "all")) {
sprintf(file, "%s/all_pad.txt", POSTPATH);
cmnd->num = 2;
} else {
sprintf(file, "%s/%s_pad.txt", POSTPATH, player->name);
}
if(cmnd->num == 2) {
if(low(cmnd->str[1][0]) == 'a') {
strcpy(player->getSock()->tempstr[0], file);
player->print("Staff notepad:\n->");
player->setFlag(P_READING_FILE);
gServer->processOutput();
player->getSock()->setState(CON_EDIT_NOTE);
player->getSock()->intrpt &= ~1;
//player->getSock()->fn = noteedit;
//player->getSock()->fnparam = 1;
return(DOPROMPT);
} else if(low(cmnd->str[1][0]) == 'd') {
unlink(file);
player->print("Clearing your notepad.\n");
return(PROMPT);
} else if(low(cmnd->str[1][0]) == 'v') {
viewFile(player->getSock(), file);
return(DOPROMPT);
} else {
player->print("invalid option.\n");
return(PROMPT);
}
} else {
viewFile(player->getSock(), file);
return(DOPROMPT);
}
}
//*********************************************************************
// noteedit
//*********************************************************************
void noteedit(Socket* sock, char *str) {
char tmpstr[40];
int ff=0;
bstring outstr = "";
Player* ply = sock->getPlayer();
if(str[0] == '.') {
ply->clearFlag(P_READING_FILE);
ply->print("Message appended.\n");
sock->restoreState();
return;
}
ff = open(sock->tempstr[0], O_RDONLY, 0);
if(ff < 0) {
ff = open(sock->tempstr[0], O_CREAT | O_RDWR, ACC);
sprintf(tmpstr, " %s\n\n", "=== Staff Notepad ===");
write(ff, tmpstr, strlen(tmpstr));
}
close(ff);
ff = open(sock->tempstr[0], O_CREAT | O_APPEND | O_RDWR, ACC);
if(ff < 0)
merror("noteedit", FATAL);
outstr = postText(str);
write(ff, outstr.c_str(), outstr.getLength());
close(ff);
sock->print("->");
gServer->processOutput();
sock->intrpt &= ~1;
return;
}
//*********************************************************************
// cmdEditHistory
//*********************************************************************
// This function allows a player to define his/her own character history
// for roleplaying purposes. -- TC
int cmdEditHistory(Player* player, cmd* cmnd) {
char file[80];
int ff=0;
if(!player->getRoom()->flagIsSet(R_SAFE_ROOM) && !player->isStaff()) {
player->print("You must be in a no pkill room in order to write your history.\n");
return(0);
}
checkDirExists(HISTPATH, true);
sprintf(file, "%s/%s.txt", HISTPATH, player->name);
ff = open(file, O_RDONLY, 0);
close(ff);
if(file_exists(file)) {
player->print("%s's history so far:\n\n", player->name);
viewLoginFile(player->getSock(), file);
player->print("\n\n");
}
broadcast(isCt, "^y### %s is editing %s character history.", player->name, player->hisHer());
player->print("You may append your character's history now.\nType '.' or '*' on a line by itself to finish.\nEach line should be NO LONGER THAN 80 CHARACTERS.\n-: ");
strcpy(player->getSock()->tempstr[0], file);
player->setFlag(P_READING_FILE);
gServer->processOutput();
player->getSock()->setState(CON_EDIT_HISTORY);
player->getSock()->intrpt &= ~1;
return(DOPROMPT);
}
//*********************************************************************
// histedit
//*********************************************************************
void histedit(Socket* sock, char *str) {
bstring outstr = "";
int ff=0;
if((str[0] == '.' || str[0] == '*') && !str[1]) {
sock->getPlayer()->clearFlag(P_READING_FILE);
sock->print("History appended.\n");
sock->restoreState();
return;
}
ff = open(sock->tempstr[0], O_CREAT | O_APPEND | O_RDWR, ACC);
if(ff < 0)
merror("histedit", FATAL);
outstr = postText(str);
write(ff, outstr.c_str(), outstr.getLength());
close(ff);
sock->print("-: ");
gServer->processOutput();
sock->intrpt &= ~1;
}
//*********************************************************************
// cmdHistory
//*********************************************************************
int cmdHistory(Player* player, cmd* cmnd) {
char file[80];
bool self = false;
if(!player->getRoom()->flagIsSet(R_SAFE_ROOM) && !player->isStaff()) {
player->print("You must be in a no pkill room in order to write your history.\n");
return(0);
}
if(cmnd->num < 2)
self = true;
else {
cmnd->str[1][0] = up(cmnd->str[1][0]);
if(!Player::exists(cmnd->str[1])) {
player->print("That player does not exist.\n");
return(0);
}
}
sprintf(file, "%s/%s.txt", HISTPATH, self ? player->name : cmnd->str[1]);
if(!file_exists(file)) {
if(self)
player->print("You haven't written a character history.\n");
else
player->print("%s hasn't written a character history.\n", cmnd->str[1]);
return(0);
}
if(self)
player->print("Your history:\n\n");
else
player->print("Current History of %s:\n\n", cmnd->str[1]);
viewFile(player->getSock(), file);
return(0);
}
//*********************************************************************
// cmdDeleteHistory
//*********************************************************************
// This function allows a player to delete their history.
int cmdDeleteHistory(Player* player, cmd* cmnd) {
char file[80];
sprintf(file, "%s/%s.txt", HISTPATH, player->name);
unlink(file);
player->print("History deleted.\n");
broadcast(isCt, "^y%s just deleted %s history.", player->name, player->hisHer());
return(0);
}
//*********************************************************************
// dmDeletemail
//*********************************************************************
// This function allows a DM to delete a player's mail file.
int dmDeletehist(Player* player, cmd* cmnd) {
char file[80];
cmnd->str[1][0] = up(cmnd->str[1][0]);
if(!Player::exists(cmnd->str[1])) {
player->print("That player does not exist.\n");
return(0);
}
sprintf(file, "%s/%s.txt", HISTPATH, cmnd->str[1]);
if(!file_exists(file)) {
player->print("%s has no history to delete.\n", cmnd->str[1]);
return(PROMPT);
}
unlink(file);
player->print("%s's history deleted.\n", cmnd->str[1]);
return(0);
}