//*********************************************** // 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 22, 1999 //************************************************* #include "MsgFolder.h" #include // for MAX_PATH #include #include #include #include "packet.h" const int MAGIC_COOKIE=1234567; CMsgFolder::CMsgFolder() { messages = NULL; nextMsgNum = 0; folderName = NULL; } // Construct folder and open it to folderName CMsgFolder::CMsgFolder(const char* folderName) { messages = NULL; nextMsgNum = 0; folderName = NULL; OpenMsgFolder(folderName); } // Close folder if any 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(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 = client_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; } client_CloseHandle(fileHandle); thisMsg.GetTopic(thisItem.topic); msgList.AddItem(msgList.length()+1,thisItem); return true; } // gets message with ID "messageId" // returns true if successful else false bool CMsgFolder::GetMsg(msgID messageId, CMessage & thisMsg) const { if (messages == NULL) return NULL; Item msgHeader; HANDLE msgFile; if (msgList.GetItem(messageId, msgHeader)) { msgFile = client_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)) { client_CloseHandle(msgFile); return false; } client_CloseHandle(msgFile); return true; } else return NULL; } // 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(!client_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(client_CreateDirectory(name,0)) { cout << "Created Directory:" << name << endl; if(!client_SetCurrentDirectory(name)) { cerr << "Could not set message folder" << name << GetLastError(); return false; } // create "messages" file with magic cookie messages = client_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(!client_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 = client_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(!client_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(!client_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; } } //**** OpenMsgFolder: client/server implementation // for simplicity, uses a flat folder naming scheme on server side bool CMsgFolder::OpenMsgFolder(const char* folder) { if( messages != NULL) CloseMsgFolder(); folderName = new char[strlen(folder)+1]; strcpy(folderName,folder); return verifyFolder(folderName); } bool CMsgFolder::CloseMsgFolder() { DWORD nBytes; if (messages == NULL) return true; // nothing to do delete folderName; folderName = NULL; client_SetFilePointer(messages,0,0,FILE_BEGIN); // rest pointer client_SetEndOfFile(messages); // truncate file if(!client_WriteFile(messages, (LPBYTE) &MAGIC_COOKIE, sizeof(int), &nBytes, NULL)) { cerr << "Could not write magic cookie!" << GetLastError(); ExitProcess(1); } if(!client_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(!client_SetCurrentDirectory("..")) { cerr << "Could not reset to parent directory" << GetLastError(); return false; } if (client_CloseHandle(messages)){ messages = NULL; return true; } else return false; }