1186c96d5SAxel Dörfler /* 2186c96d5SAxel Dörfler * Copyright 2013, Axel Dörfler, axeld@pinc-software.de. 3186c96d5SAxel Dörfler * Distributed under the terms of the MIT License. 4186c96d5SAxel Dörfler */ 5186c96d5SAxel Dörfler 6186c96d5SAxel Dörfler 7186c96d5SAxel Dörfler #include "IMAPProtocol.h" 8186c96d5SAxel Dörfler 9186c96d5SAxel Dörfler #include <Directory.h> 10186c96d5SAxel Dörfler 11186c96d5SAxel Dörfler #include "IMAPConnectionWorker.h" 12a4bdd26dSAxel Dörfler #include "IMAPFolder.h" 13a4bdd26dSAxel Dörfler #include "Utilities.h" 14186c96d5SAxel Dörfler 15186c96d5SAxel Dörfler 16186c96d5SAxel Dörfler IMAPProtocol::IMAPProtocol(const BMailAccountSettings& settings) 17186c96d5SAxel Dörfler : 18186c96d5SAxel Dörfler BInboundMailProtocol(settings), 1928ee6c28SAxel Dörfler fSettings(settings.Name(), settings.InboundSettings()), 207993ddfaSAxel Dörfler fWorkers(5, false) 21186c96d5SAxel Dörfler { 22186c96d5SAxel Dörfler BPath destination = fSettings.Destination(); 23186c96d5SAxel Dörfler 24186c96d5SAxel Dörfler status_t status = create_directory(destination.Path(), 0755); 25186c96d5SAxel Dörfler if (status != B_OK) { 2628ee6c28SAxel Dörfler fprintf(stderr, "IMAP: Could not create destination directory %s: %s\n", 27186c96d5SAxel Dörfler destination.Path(), strerror(status)); 28186c96d5SAxel Dörfler } 29186c96d5SAxel Dörfler 30186c96d5SAxel Dörfler PostMessage(B_READY_TO_RUN); 31186c96d5SAxel Dörfler } 32186c96d5SAxel Dörfler 33186c96d5SAxel Dörfler 34186c96d5SAxel Dörfler IMAPProtocol::~IMAPProtocol() 35186c96d5SAxel Dörfler { 36186c96d5SAxel Dörfler } 37186c96d5SAxel Dörfler 38186c96d5SAxel Dörfler 39186c96d5SAxel Dörfler status_t 407993ddfaSAxel Dörfler IMAPProtocol::CheckSubscribedFolders(IMAP::Protocol& protocol, bool idle) 41adbe8fc9SAxel Dörfler { 42adbe8fc9SAxel Dörfler // Get list of subscribed folders 43adbe8fc9SAxel Dörfler 44a4bdd26dSAxel Dörfler StringList newFolders; 45a4bdd26dSAxel Dörfler BString separator; 46a4bdd26dSAxel Dörfler status_t status = protocol.GetSubscribedFolders(newFolders, separator); 47adbe8fc9SAxel Dörfler if (status != B_OK) 48adbe8fc9SAxel Dörfler return status; 49adbe8fc9SAxel Dörfler 50adbe8fc9SAxel Dörfler // Determine how many new mailboxes we have 51adbe8fc9SAxel Dörfler 52a4bdd26dSAxel Dörfler StringList::iterator folderIterator = newFolders.begin(); 53a4bdd26dSAxel Dörfler while (folderIterator != newFolders.end()) { 54a4bdd26dSAxel Dörfler if (fFolders.find(*folderIterator) != fFolders.end()) 55a4bdd26dSAxel Dörfler folderIterator = newFolders.erase(folderIterator); 56a4bdd26dSAxel Dörfler else 57a4bdd26dSAxel Dörfler folderIterator++; 58adbe8fc9SAxel Dörfler } 59adbe8fc9SAxel Dörfler 60a4bdd26dSAxel Dörfler int32 totalMailboxes = fFolders.size() + newFolders.size(); 61a4bdd26dSAxel Dörfler int32 workersWanted = 1; 627993ddfaSAxel Dörfler if (idle) 63a4bdd26dSAxel Dörfler workersWanted = std::min(fSettings.MaxConnections(), totalMailboxes); 64adbe8fc9SAxel Dörfler 65a4bdd26dSAxel Dörfler if (newFolders.empty() && fWorkers.CountItems() == workersWanted) { 66a4bdd26dSAxel Dörfler // Nothing to do - we've already distributed everything 67a4bdd26dSAxel Dörfler return B_OK; 68a4bdd26dSAxel Dörfler } 69adbe8fc9SAxel Dörfler 70a4bdd26dSAxel Dörfler // Remove mailboxes from workers 71a4bdd26dSAxel Dörfler for (int32 i = 0; i < fWorkers.CountItems(); i++) { 72a4bdd26dSAxel Dörfler fWorkers.ItemAt(i)->RemoveAllMailboxes(); 73a4bdd26dSAxel Dörfler } 74a4bdd26dSAxel Dörfler 75a4bdd26dSAxel Dörfler // Create/remove connection workers as allowed and needed 76a4bdd26dSAxel Dörfler while (fWorkers.CountItems() < workersWanted) { 77adbe8fc9SAxel Dörfler IMAPConnectionWorker* worker = new IMAPConnectionWorker(*this, 78adbe8fc9SAxel Dörfler fSettings); 79adbe8fc9SAxel Dörfler if (!fWorkers.AddItem(worker)) { 80adbe8fc9SAxel Dörfler delete worker; 81adbe8fc9SAxel Dörfler break; 82adbe8fc9SAxel Dörfler } 83adbe8fc9SAxel Dörfler 847993ddfaSAxel Dörfler status = worker->Run(); 857993ddfaSAxel Dörfler if (status != B_OK) { 867993ddfaSAxel Dörfler fWorkers.RemoveItem(worker); 877993ddfaSAxel Dörfler delete worker; 88adbe8fc9SAxel Dörfler } 897993ddfaSAxel Dörfler } 907993ddfaSAxel Dörfler 91a4bdd26dSAxel Dörfler while (fWorkers.CountItems() > workersWanted) { 92a4bdd26dSAxel Dörfler IMAPConnectionWorker* worker 93a4bdd26dSAxel Dörfler = fWorkers.RemoveItemAt(fWorkers.CountItems() - 1); 94a4bdd26dSAxel Dörfler worker->Quit(); 95adbe8fc9SAxel Dörfler } 96adbe8fc9SAxel Dörfler 97a4bdd26dSAxel Dörfler // Update known mailboxes 98a4bdd26dSAxel Dörfler folderIterator = newFolders.begin(); 99a4bdd26dSAxel Dörfler for (; folderIterator != newFolders.end(); folderIterator++) { 100a4bdd26dSAxel Dörfler const BString& mailbox = *folderIterator; 101a4bdd26dSAxel Dörfler fFolders.insert(std::make_pair(mailbox, 102a4bdd26dSAxel Dörfler _CreateFolder(mailbox, separator))); 103a4bdd26dSAxel Dörfler } 104adbe8fc9SAxel Dörfler 105a4bdd26dSAxel Dörfler // Distribute the mailboxes evenly to the workers 106a4bdd26dSAxel Dörfler FolderMap::iterator iterator = fFolders.begin(); 107adbe8fc9SAxel Dörfler int32 index = 0; 108a4bdd26dSAxel Dörfler for (; iterator != fFolders.end(); iterator++) { 109a4bdd26dSAxel Dörfler fWorkers.ItemAt(index)->AddMailbox(iterator->second); 110adbe8fc9SAxel Dörfler index = (index + 1) % fWorkers.CountItems(); 111adbe8fc9SAxel Dörfler } 112adbe8fc9SAxel Dörfler 1137993ddfaSAxel Dörfler // Start waiting workers 1144b2c5571SAxel Dörfler return _EnqueueCheckMailboxes(); 115adbe8fc9SAxel Dörfler } 116adbe8fc9SAxel Dörfler 117adbe8fc9SAxel Dörfler 118229c7773SAxel Dörfler void 119229c7773SAxel Dörfler IMAPProtocol::WorkerQuit(IMAPConnectionWorker* worker) 120229c7773SAxel Dörfler { 121229c7773SAxel Dörfler fWorkers.RemoveItem(worker); 122229c7773SAxel Dörfler } 123229c7773SAxel Dörfler 124229c7773SAxel Dörfler 125eba458b9SAxel Dörfler void 126*1052525dSAxel Dörfler IMAPProtocol::MessageStored(IMAPFolder& folder, entry_ref& ref, BFile& stream, 127*1052525dSAxel Dörfler uint32 fetchFlags) 128eba458b9SAxel Dörfler { 129eba458b9SAxel Dörfler if ((fetchFlags & IMAP::kFetchHeader) != 0) 130eba458b9SAxel Dörfler NotifyHeaderFetched(ref, &stream); 131eba458b9SAxel Dörfler if ((fetchFlags & IMAP::kFetchBody) != 0) 132eba458b9SAxel Dörfler NotifyBodyFetched(ref, &stream); 133eba458b9SAxel Dörfler } 134eba458b9SAxel Dörfler 135eba458b9SAxel Dörfler 136adbe8fc9SAxel Dörfler status_t 137186c96d5SAxel Dörfler IMAPProtocol::SyncMessages() 138186c96d5SAxel Dörfler { 139186c96d5SAxel Dörfler puts("IMAP: sync"); 140adbe8fc9SAxel Dörfler 141adbe8fc9SAxel Dörfler if (fWorkers.IsEmpty()) { 142adbe8fc9SAxel Dörfler // Create main (and possibly initial) connection worker 143adbe8fc9SAxel Dörfler IMAPConnectionWorker* worker = new IMAPConnectionWorker(*this, 144adbe8fc9SAxel Dörfler fSettings, true); 145adbe8fc9SAxel Dörfler if (!fWorkers.AddItem(worker)) { 146adbe8fc9SAxel Dörfler delete worker; 147adbe8fc9SAxel Dörfler return B_NO_MEMORY; 148adbe8fc9SAxel Dörfler } 149adbe8fc9SAxel Dörfler 150229c7773SAxel Dörfler worker->EnqueueCheckSubscribedFolders(); 151a4bdd26dSAxel Dörfler return worker->Run(); 152adbe8fc9SAxel Dörfler } 153adbe8fc9SAxel Dörfler 1544b2c5571SAxel Dörfler return _EnqueueCheckMailboxes(); 155186c96d5SAxel Dörfler } 156186c96d5SAxel Dörfler 157186c96d5SAxel Dörfler 158186c96d5SAxel Dörfler status_t 159186c96d5SAxel Dörfler IMAPProtocol::FetchBody(const entry_ref& ref) 160186c96d5SAxel Dörfler { 161186c96d5SAxel Dörfler printf("IMAP: fetch body %s\n", ref.name); 162186c96d5SAxel Dörfler return B_ERROR; 163186c96d5SAxel Dörfler } 164186c96d5SAxel Dörfler 165186c96d5SAxel Dörfler 166186c96d5SAxel Dörfler status_t 167186c96d5SAxel Dörfler IMAPProtocol::MarkMessageAsRead(const entry_ref& ref, read_flags flags) 168186c96d5SAxel Dörfler { 169186c96d5SAxel Dörfler printf("IMAP: mark as read %s: %d\n", ref.name, flags); 170186c96d5SAxel Dörfler return B_ERROR; 171186c96d5SAxel Dörfler } 172186c96d5SAxel Dörfler 173186c96d5SAxel Dörfler 174186c96d5SAxel Dörfler status_t 175186c96d5SAxel Dörfler IMAPProtocol::DeleteMessage(const entry_ref& ref) 176186c96d5SAxel Dörfler { 177186c96d5SAxel Dörfler printf("IMAP: delete message %s\n", ref.name); 178186c96d5SAxel Dörfler return B_ERROR; 179186c96d5SAxel Dörfler } 180186c96d5SAxel Dörfler 181186c96d5SAxel Dörfler 182186c96d5SAxel Dörfler status_t 183186c96d5SAxel Dörfler IMAPProtocol::AppendMessage(const entry_ref& ref) 184186c96d5SAxel Dörfler { 185186c96d5SAxel Dörfler printf("IMAP: append message %s\n", ref.name); 186186c96d5SAxel Dörfler return B_ERROR; 187186c96d5SAxel Dörfler } 188186c96d5SAxel Dörfler 189186c96d5SAxel Dörfler 190186c96d5SAxel Dörfler void 191186c96d5SAxel Dörfler IMAPProtocol::MessageReceived(BMessage* message) 192186c96d5SAxel Dörfler { 193186c96d5SAxel Dörfler switch (message->what) { 194186c96d5SAxel Dörfler case B_READY_TO_RUN: 195186c96d5SAxel Dörfler ReadyToRun(); 196186c96d5SAxel Dörfler break; 197adbe8fc9SAxel Dörfler 198adbe8fc9SAxel Dörfler default: 199adbe8fc9SAxel Dörfler BInboundMailProtocol::MessageReceived(message); 200adbe8fc9SAxel Dörfler break; 201186c96d5SAxel Dörfler } 202186c96d5SAxel Dörfler } 203186c96d5SAxel Dörfler 204186c96d5SAxel Dörfler 205186c96d5SAxel Dörfler void 206186c96d5SAxel Dörfler IMAPProtocol::ReadyToRun() 207186c96d5SAxel Dörfler { 208adbe8fc9SAxel Dörfler puts("IMAP: ready to run!"); 209adbe8fc9SAxel Dörfler if (fSettings.IdleMode()) 210adbe8fc9SAxel Dörfler SyncMessages(); 211186c96d5SAxel Dörfler } 212186c96d5SAxel Dörfler 213186c96d5SAxel Dörfler 214a4bdd26dSAxel Dörfler IMAPFolder* 215a4bdd26dSAxel Dörfler IMAPProtocol::_CreateFolder(const BString& mailbox, const BString& separator) 216a4bdd26dSAxel Dörfler { 217a4bdd26dSAxel Dörfler BString name = MailboxToFolderName(mailbox, separator); 218a4bdd26dSAxel Dörfler 219a4bdd26dSAxel Dörfler BPath path(fSettings.Destination()); 220a4bdd26dSAxel Dörfler if (path.Append(name.String()) != B_OK) { 221a4bdd26dSAxel Dörfler fprintf(stderr, "Could not append path: %s\n", name.String()); 222a4bdd26dSAxel Dörfler return NULL; 223a4bdd26dSAxel Dörfler } 224a4bdd26dSAxel Dörfler 225a4bdd26dSAxel Dörfler status_t status = create_directory(path.Path(), 0755); 226a4bdd26dSAxel Dörfler if (status != B_OK) { 227a4bdd26dSAxel Dörfler fprintf(stderr, "Could not create path %s: %s\n", path.Path(), 228a4bdd26dSAxel Dörfler strerror(status)); 229a4bdd26dSAxel Dörfler return NULL; 230a4bdd26dSAxel Dörfler } 231a4bdd26dSAxel Dörfler 232a4bdd26dSAxel Dörfler entry_ref ref; 233a4bdd26dSAxel Dörfler status = get_ref_for_path(path.Path(), &ref); 234a4bdd26dSAxel Dörfler if (status != B_OK) { 235a4bdd26dSAxel Dörfler fprintf(stderr, "Could not get ref for %s: %s\n", path.Path(), 236a4bdd26dSAxel Dörfler strerror(status)); 237a4bdd26dSAxel Dörfler return NULL; 238a4bdd26dSAxel Dörfler } 239a4bdd26dSAxel Dörfler 240eba458b9SAxel Dörfler return new IMAPFolder(*this, mailbox, ref); 241a4bdd26dSAxel Dörfler } 242a4bdd26dSAxel Dörfler 243a4bdd26dSAxel Dörfler 2444b2c5571SAxel Dörfler status_t 2454b2c5571SAxel Dörfler IMAPProtocol::_EnqueueCheckMailboxes() 2464b2c5571SAxel Dörfler { 2474b2c5571SAxel Dörfler for (int32 i = 0; i < fWorkers.CountItems(); i++) { 2484b2c5571SAxel Dörfler fWorkers.ItemAt(i)->EnqueueCheckMailboxes(); 2494b2c5571SAxel Dörfler } 2504b2c5571SAxel Dörfler 2514b2c5571SAxel Dörfler return B_OK; 2524b2c5571SAxel Dörfler } 2534b2c5571SAxel Dörfler 2544b2c5571SAxel Dörfler 255186c96d5SAxel Dörfler // #pragma mark - 256186c96d5SAxel Dörfler 257186c96d5SAxel Dörfler 258186c96d5SAxel Dörfler extern "C" BInboundMailProtocol* 259186c96d5SAxel Dörfler instantiate_inbound_protocol(const BMailAccountSettings& settings) 260186c96d5SAxel Dörfler { 261186c96d5SAxel Dörfler return new IMAPProtocol(settings); 262186c96d5SAxel Dörfler } 263