//*********************************************** // 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 an identifier in the first place 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 be able to rebuild messages file // ALTERNATE: // Store all messages in one file (like PINE). // AUTHOR: Chris Wild // DATE: July 25, 1997 // Revised: January 17, 1999 //************************************************* #include "MsgFolder.h" #include // for MAX_PATH #include #include #include // for WIN32 APIs const int MAGIC_COOKIE=1234567; // to catch messed up aborts, etc CMsgFolder::CMsgFolder() { messages = NULL; nextMsgNum = 0; } // opens (or creates a folder called "folderName" in current directory CMsgFolder::CMsgFolder(const char* folder) { char currentDir[MAX_PATH]; int currentLen = GetCurrentDirectory(MAX_PATH, currentDir); messages = NULL; nextMsgNum = 0; 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); } // 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) { 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 bool CMsgFolder::GetMsg(msgID messageId, CMessage & thisMsg) const { if (messages == NULL) return false; 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); } if(!thisMsg.ReadMsg(msgFile)) { CloseHandle(msgFile); return false; } CloseHandle(msgFile); return true; } else return false; } // Deletes message with msgID "messageID" // removes from MsgList and deletes Message file // returns false if 1) no folder open // 2) message does not exists in list // 3) file cannot be deleted // returns true is successfull bool CMsgFolder::DeleteMsg(msgID messageID) { if(messages == NULL) return false; Item msgHeader; if(msgList.GetItem(messageID, msgHeader)) { if(!DeleteFile(msgHeader.fileName)) { cerr << "Error: " << GetLastError() << " when deleting file: " << msgHeader.fileName << endl; ExitProcess(1); } if(msgList.DeleteItem(messageID)) return true; else return false; } 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 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; } nextMsgNum = 0; 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; } return true; } } bool CMsgFolder::OpenMsgFolder(const char* folder) { char currentDir[MAX_PATH]; if( messages != NULL) CloseMsgFolder(); 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); // reset pointer SetEndOfFile(messages); // truncate file 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); } // delete list while(msgList.DeleteItem(1)) ; // delete first item continuously until done // now return to parent directory if(!SetCurrentDirectory("..")) { cerr << "Could not reset to parent directory" << GetLastError(); return false; } if (CloseHandle(messages)){ messages = NULL; return true; } else return false; }