//*********************************************** // Handles Message Folders // A message folder is a directory in the file system // This directory contains a message files (one for each message) // and a special file called "messages" // This file contains a code in the first byte which identifies it as a messagefolder file // If the folder does not exist it is created, If it exists it must contain a "messages" file // else this is considered an inconsistent state of the messagefolder object. // TODO: // Should restore working directory after closing folder // Should be able to rebuild messages file // ALTERNATE: // Store all messages in one file (like PINE). // AUTHOR: Chris Wild // DATE: July 25, 1997 //************************************************* #include "MsgFolder.h" #include // for MAX_PATH #include #include #include const int MAGIC_COOKIE=1234567; CMsgFolder::CMsgFolder():messages(NULL), nextMsgNum(0) { /*char* tempName = "c:\\MsgFldr"; folderName = new char[strlen(tempName)+1]; strncpy(folderName, tempName, strlen(tempName)); verifyFolder(folderName); */ } // opens (or creates a folder called "folderName" in current directory CMsgFolder::CMsgFolder(const char* folder):messages(NULL), nextMsgNum(0) { char currentDir[MAX_PATH]; int currentLen = GetCurrentDirectory(MAX_PATH, currentDir); folderName = new char[currentLen + strlen(folder)+2]; strncpy(folderName,currentDir,strlen(currentDir)); strncpy(folderName+strlen(currentDir),"\\",1); strncpy(folderName+strlen(currentDir)+1, folder, strlen(folder)); strncpy(folderName+strlen(currentDir)+1+strlen(folder), "\0",1); verifyFolder(folderName); } // opens (or creates) a folder called "folderName in "path" CMsgFolder::CMsgFolder(const char* path, const char* folderName):messages(NULL), nextMsgNum(0) { } // Writes out open messages and folder information CMsgFolder::~CMsgFolder() { if( messages != NULL) CloseMsgFolder(); } // Puts a message in the folder // Will save message in its own file // Names are of the form "MSGxxx" where xxx is a number from // 1 to max number of messages ever created. // new messages are put at the end of the list of current messages // Save maximum buffer sizes for topic and text fields. bool CMsgFolder::PostMsg(const CMessage& thisMsg) { // 1 to the watershed of number of messages?? HANDLE fileHandle; Item thisItem; if (messages == NULL) // no message folder opened return FALSE; ZeroMemory(thisItem.fileName, sizeof(thisItem.fileName)); ZeroMemory(thisItem.topic, sizeof(thisItem.topic)); sprintf(thisItem.fileName, "MSG%d", ++nextMsgNum); fileHandle = CreateFile(thisItem.fileName,GENERIC_WRITE,0,0,CREATE_NEW,0,0); if(fileHandle == INVALID_HANDLE_VALUE) { cerr << "Error: " << GetLastError() << " when creating file:" << thisItem.fileName << endl; return FALSE; } if(!thisMsg.WriteMsg(fileHandle)) { return FALSE; } CloseHandle(fileHandle); thisMsg.GetTopic(thisItem.topic); msgList.AddItem(msgList.length()+1,thisItem); return TRUE; } // gets message with ID "messageId // if message ID does not exist returns EMPTY message CMessage CMsgFolder::GetMsg(msgID messageId) const { if (messages == NULL) return NULL; Item msgHeader; HANDLE msgFile; if (msgList.GetItem(messageId, msgHeader)) { msgFile = CreateFile(msgHeader.fileName,GENERIC_READ,0,0,OPEN_EXISTING,0,0); if(msgFile == INVALID_HANDLE_VALUE) { cerr << "Error: " << GetLastError() << " when opening file: " << msgHeader.fileName << endl; ExitProcess(1); } CMessage msg(msgFile); // create a new message and initialize from msgFile CloseHandle(msgFile); return msg; } else return NULL; } bool CMsgFolder::DeleteMsg(msgID messageID) { if(messages == NULL) return false; if(msgList.DeleteItem(messageID)) return TRUE; else return FALSE; } // PRE: message with "messageID" exists // topic points to a string big enough to hold topic string // POST: if exists, returns true and topic of this message // else returns false bool CMsgFolder::GetMsgTopic(msgID messageId, char* topic) const { if(messages == NULL) return false; Item thisItem; if(msgList.GetItem(messageId, thisItem)) { strncpy(topic, thisItem.topic, SIZE_TOPIC+1); return TRUE; } else return FALSE; } int CMsgFolder::NumMsgs() const { return msgList.length(); } // **** // verifyFolder - verifies then creates/opens message folder bool CMsgFolder::verifyFolder(const char* name) { DWORD nBytes; if(CreateDirectory(name,0)) { cout << "Created Directory:" << name << endl; if(!SetCurrentDirectory(name)) { cerr << "Could not set message folder" << name << GetLastError(); return FALSE; } // create "messages" file with magic cookie messages = CreateFile("messages",GENERIC_WRITE,0,0,CREATE_NEW,0,0); if(messages == INVALID_HANDLE_VALUE) { cerr << "Could not create messages file" << GetLastError(); return FALSE; } return TRUE; } else { if(!SetCurrentDirectory(name)) { cerr << "Could not set message folder" << name << GetLastError(); return FALSE; } // Now check if this folder contains a "messages" file with the magic cookie messages = CreateFile( "messages", GENERIC_READ|GENERIC_WRITE, // read then write this file 0,0, OPEN_EXISTING, 0,0); if(messages == INVALID_HANDLE_VALUE) { cerr << "Could not open messages file" << GetLastError(); return FALSE; } int cookie; if(!ReadFile(messages, (LPBYTE) &cookie, sizeof(cookie), &nBytes, NULL)) { cerr << "Could not read magic cookie!" << GetLastError(); return FALSE; } if(cookie != MAGIC_COOKIE) { cerr << "no magic cookie!\n"; return FALSE; } if(!ReadFile(messages, (LPBYTE) &nextMsgNum, sizeof(nextMsgNum), &nBytes, NULL)) { cerr << "Could not nMessages!" << GetLastError(); return FALSE; } // now read messages list if(!msgList.ReadListMsgs(messages)) { cerr << "Could not read message list\n"; return FALSE; } // now set file pointer to beginning for update return TRUE; } } bool CMsgFolder::OpenMsgFolder(const char* folder) { char currentDir[MAX_PATH]; int currentLen = GetCurrentDirectory(MAX_PATH, currentDir); folderName = new char[currentLen + strlen(folder)+2]; strncpy(folderName,currentDir,strlen(currentDir)); strncpy(folderName+strlen(currentDir),"\\",1); strncpy(folderName+strlen(currentDir)+1, folder, strlen(folder)); strncpy(folderName+strlen(currentDir)+1+strlen(folder), "\0",1); return verifyFolder(folderName); } bool CMsgFolder::CloseMsgFolder() { DWORD nBytes; if (messages == NULL) return TRUE; // nothing to do delete folderName; folderName = NULL; SetFilePointer(messages,0,0,FILE_BEGIN); // rest pointer if(!WriteFile(messages, (LPBYTE) &MAGIC_COOKIE, sizeof(int), &nBytes, NULL)) { cerr << "Could not write magic cookie!" << GetLastError(); ExitProcess(1); } if(!WriteFile(messages, (LPBYTE) &nextMsgNum, sizeof(nextMsgNum), &nBytes, NULL)) { cerr << "Could not write nMessages!" << GetLastError(); ExitProcess(1); } if(!msgList.WriteListMsgs(messages)) { cerr << "Could not write messages!\n" ; ExitProcess(1); } if (CloseHandle(messages)){ messages = NULL; return TRUE; } else return FALSE; }