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" 12*a4bdd26dSAxel Dörfler #include "IMAPFolder.h" 13*a4bdd26dSAxel 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), 19186c96d5SAxel Dörfler fSettings(settings.InboundSettings()) 20186c96d5SAxel Dörfler { 21186c96d5SAxel Dörfler BPath destination = fSettings.Destination(); 22186c96d5SAxel Dörfler 23186c96d5SAxel Dörfler status_t status = create_directory(destination.Path(), 0755); 24186c96d5SAxel Dörfler if (status != B_OK) { 25186c96d5SAxel Dörfler fprintf(stderr, "imap: Could not create destination directory %s: %s\n", 26186c96d5SAxel Dörfler destination.Path(), strerror(status)); 27186c96d5SAxel Dörfler } 28186c96d5SAxel Dörfler 29*a4bdd26dSAxel Dörfler status = _CreateFolderChangeSemaphore(); 30*a4bdd26dSAxel Dörfler if (status != B_OK) 31*a4bdd26dSAxel Dörfler fprintf(stderr, "imap: Failed to create sem: %s\n", strerror(status)); 32*a4bdd26dSAxel Dörfler 33186c96d5SAxel Dörfler PostMessage(B_READY_TO_RUN); 34186c96d5SAxel Dörfler } 35186c96d5SAxel Dörfler 36186c96d5SAxel Dörfler 37186c96d5SAxel Dörfler IMAPProtocol::~IMAPProtocol() 38186c96d5SAxel Dörfler { 39186c96d5SAxel Dörfler } 40186c96d5SAxel Dörfler 41186c96d5SAxel Dörfler 42186c96d5SAxel Dörfler status_t 43adbe8fc9SAxel Dörfler IMAPProtocol::CheckSubscribedFolders(IMAP::Protocol& protocol) 44adbe8fc9SAxel Dörfler { 45adbe8fc9SAxel Dörfler // Get list of subscribed folders 46adbe8fc9SAxel Dörfler 47*a4bdd26dSAxel Dörfler StringList newFolders; 48*a4bdd26dSAxel Dörfler BString separator; 49*a4bdd26dSAxel Dörfler status_t status = protocol.GetSubscribedFolders(newFolders, separator); 50adbe8fc9SAxel Dörfler if (status != B_OK) 51adbe8fc9SAxel Dörfler return status; 52adbe8fc9SAxel Dörfler 53adbe8fc9SAxel Dörfler // Determine how many new mailboxes we have 54adbe8fc9SAxel Dörfler 55*a4bdd26dSAxel Dörfler StringList::iterator folderIterator = newFolders.begin(); 56*a4bdd26dSAxel Dörfler while (folderIterator != newFolders.end()) { 57*a4bdd26dSAxel Dörfler if (fFolders.find(*folderIterator) != fFolders.end()) 58*a4bdd26dSAxel Dörfler folderIterator = newFolders.erase(folderIterator); 59*a4bdd26dSAxel Dörfler else 60*a4bdd26dSAxel Dörfler folderIterator++; 61adbe8fc9SAxel Dörfler } 62adbe8fc9SAxel Dörfler 63*a4bdd26dSAxel Dörfler int32 totalMailboxes = fFolders.size() + newFolders.size(); 64*a4bdd26dSAxel Dörfler int32 workersWanted = 1; 65*a4bdd26dSAxel Dörfler if (fSettings.IdleMode()) 66*a4bdd26dSAxel Dörfler workersWanted = std::min(fSettings.MaxConnections(), totalMailboxes); 67adbe8fc9SAxel Dörfler 68*a4bdd26dSAxel Dörfler if (newFolders.empty() && fWorkers.CountItems() == workersWanted) { 69*a4bdd26dSAxel Dörfler // Nothing to do - we've already distributed everything 70*a4bdd26dSAxel Dörfler return B_OK; 71*a4bdd26dSAxel Dörfler } 72adbe8fc9SAxel Dörfler 73*a4bdd26dSAxel Dörfler // Remove mailboxes from workers 74*a4bdd26dSAxel Dörfler for (int32 i = 0; i < fWorkers.CountItems(); i++) { 75*a4bdd26dSAxel Dörfler fWorkers.ItemAt(i)->RemoveAllMailboxes(); 76*a4bdd26dSAxel Dörfler } 77*a4bdd26dSAxel Dörfler 78*a4bdd26dSAxel Dörfler // Create/remove connection workers as allowed and needed 79*a4bdd26dSAxel Dörfler while (fWorkers.CountItems() < workersWanted) { 80adbe8fc9SAxel Dörfler IMAPConnectionWorker* worker = new IMAPConnectionWorker(*this, 81adbe8fc9SAxel Dörfler fSettings); 82adbe8fc9SAxel Dörfler if (!fWorkers.AddItem(worker)) { 83adbe8fc9SAxel Dörfler delete worker; 84adbe8fc9SAxel Dörfler break; 85adbe8fc9SAxel Dörfler } 86adbe8fc9SAxel Dörfler 87*a4bdd26dSAxel Dörfler worker->Run(); 88adbe8fc9SAxel Dörfler } 89*a4bdd26dSAxel Dörfler while (fWorkers.CountItems() > workersWanted) { 90*a4bdd26dSAxel Dörfler IMAPConnectionWorker* worker 91*a4bdd26dSAxel Dörfler = fWorkers.RemoveItemAt(fWorkers.CountItems() - 1); 92*a4bdd26dSAxel Dörfler worker->Quit(); 93adbe8fc9SAxel Dörfler } 94adbe8fc9SAxel Dörfler 95*a4bdd26dSAxel Dörfler // Update known mailboxes 96*a4bdd26dSAxel Dörfler folderIterator = newFolders.begin(); 97*a4bdd26dSAxel Dörfler for (; folderIterator != newFolders.end(); folderIterator++) { 98*a4bdd26dSAxel Dörfler const BString& mailbox = *folderIterator; 99*a4bdd26dSAxel Dörfler fFolders.insert(std::make_pair(mailbox, 100*a4bdd26dSAxel Dörfler _CreateFolder(mailbox, separator))); 101*a4bdd26dSAxel Dörfler } 102adbe8fc9SAxel Dörfler 103*a4bdd26dSAxel Dörfler // Distribute the mailboxes evenly to the workers 104*a4bdd26dSAxel Dörfler FolderMap::iterator iterator = fFolders.begin(); 105adbe8fc9SAxel Dörfler int32 index = 0; 106*a4bdd26dSAxel Dörfler for (; iterator != fFolders.end(); iterator++) { 107*a4bdd26dSAxel Dörfler fWorkers.ItemAt(index)->AddMailbox(iterator->second); 108adbe8fc9SAxel Dörfler index = (index + 1) % fWorkers.CountItems(); 109adbe8fc9SAxel Dörfler } 110adbe8fc9SAxel Dörfler 111*a4bdd26dSAxel Dörfler // Restart waiting workers 112*a4bdd26dSAxel Dörfler delete_sem(fFolderChangeSemaphore); 113*a4bdd26dSAxel Dörfler return _CreateFolderChangeSemaphore(); 114adbe8fc9SAxel Dörfler } 115adbe8fc9SAxel Dörfler 116adbe8fc9SAxel Dörfler 117adbe8fc9SAxel Dörfler status_t 118186c96d5SAxel Dörfler IMAPProtocol::SyncMessages() 119186c96d5SAxel Dörfler { 120186c96d5SAxel Dörfler puts("IMAP: sync"); 121adbe8fc9SAxel Dörfler 122adbe8fc9SAxel Dörfler if (fWorkers.IsEmpty()) { 123adbe8fc9SAxel Dörfler // Create main (and possibly initial) connection worker 124adbe8fc9SAxel Dörfler IMAPConnectionWorker* worker = new IMAPConnectionWorker(*this, 125adbe8fc9SAxel Dörfler fSettings, true); 126adbe8fc9SAxel Dörfler if (!fWorkers.AddItem(worker)) { 127adbe8fc9SAxel Dörfler delete worker; 128adbe8fc9SAxel Dörfler return B_NO_MEMORY; 129adbe8fc9SAxel Dörfler } 130adbe8fc9SAxel Dörfler 131*a4bdd26dSAxel Dörfler return worker->Run(); 132adbe8fc9SAxel Dörfler } 133adbe8fc9SAxel Dörfler 134adbe8fc9SAxel Dörfler return B_OK; 135186c96d5SAxel Dörfler } 136186c96d5SAxel Dörfler 137186c96d5SAxel Dörfler 138186c96d5SAxel Dörfler status_t 139186c96d5SAxel Dörfler IMAPProtocol::FetchBody(const entry_ref& ref) 140186c96d5SAxel Dörfler { 141186c96d5SAxel Dörfler printf("IMAP: fetch body %s\n", ref.name); 142186c96d5SAxel Dörfler return B_ERROR; 143186c96d5SAxel Dörfler } 144186c96d5SAxel Dörfler 145186c96d5SAxel Dörfler 146186c96d5SAxel Dörfler status_t 147186c96d5SAxel Dörfler IMAPProtocol::MarkMessageAsRead(const entry_ref& ref, read_flags flags) 148186c96d5SAxel Dörfler { 149186c96d5SAxel Dörfler printf("IMAP: mark as read %s: %d\n", ref.name, flags); 150186c96d5SAxel Dörfler return B_ERROR; 151186c96d5SAxel Dörfler } 152186c96d5SAxel Dörfler 153186c96d5SAxel Dörfler 154186c96d5SAxel Dörfler status_t 155186c96d5SAxel Dörfler IMAPProtocol::DeleteMessage(const entry_ref& ref) 156186c96d5SAxel Dörfler { 157186c96d5SAxel Dörfler printf("IMAP: delete message %s\n", ref.name); 158186c96d5SAxel Dörfler return B_ERROR; 159186c96d5SAxel Dörfler } 160186c96d5SAxel Dörfler 161186c96d5SAxel Dörfler 162186c96d5SAxel Dörfler status_t 163186c96d5SAxel Dörfler IMAPProtocol::AppendMessage(const entry_ref& ref) 164186c96d5SAxel Dörfler { 165186c96d5SAxel Dörfler printf("IMAP: append message %s\n", ref.name); 166186c96d5SAxel Dörfler return B_ERROR; 167186c96d5SAxel Dörfler } 168186c96d5SAxel Dörfler 169186c96d5SAxel Dörfler 170186c96d5SAxel Dörfler void 171186c96d5SAxel Dörfler IMAPProtocol::MessageReceived(BMessage* message) 172186c96d5SAxel Dörfler { 173186c96d5SAxel Dörfler switch (message->what) { 174186c96d5SAxel Dörfler case B_READY_TO_RUN: 175186c96d5SAxel Dörfler ReadyToRun(); 176186c96d5SAxel Dörfler break; 177adbe8fc9SAxel Dörfler 178adbe8fc9SAxel Dörfler default: 179adbe8fc9SAxel Dörfler BInboundMailProtocol::MessageReceived(message); 180adbe8fc9SAxel Dörfler break; 181186c96d5SAxel Dörfler } 182186c96d5SAxel Dörfler } 183186c96d5SAxel Dörfler 184186c96d5SAxel Dörfler 185186c96d5SAxel Dörfler void 186186c96d5SAxel Dörfler IMAPProtocol::ReadyToRun() 187186c96d5SAxel Dörfler { 188adbe8fc9SAxel Dörfler puts("IMAP: ready to run!"); 189adbe8fc9SAxel Dörfler if (fSettings.IdleMode()) 190adbe8fc9SAxel Dörfler SyncMessages(); 191186c96d5SAxel Dörfler } 192186c96d5SAxel Dörfler 193186c96d5SAxel Dörfler 194*a4bdd26dSAxel Dörfler IMAPFolder* 195*a4bdd26dSAxel Dörfler IMAPProtocol::_CreateFolder(const BString& mailbox, const BString& separator) 196*a4bdd26dSAxel Dörfler { 197*a4bdd26dSAxel Dörfler BString name = MailboxToFolderName(mailbox, separator); 198*a4bdd26dSAxel Dörfler 199*a4bdd26dSAxel Dörfler BPath path(fSettings.Destination()); 200*a4bdd26dSAxel Dörfler if (path.Append(name.String()) != B_OK) { 201*a4bdd26dSAxel Dörfler fprintf(stderr, "Could not append path: %s\n", name.String()); 202*a4bdd26dSAxel Dörfler return NULL; 203*a4bdd26dSAxel Dörfler } 204*a4bdd26dSAxel Dörfler 205*a4bdd26dSAxel Dörfler status_t status = create_directory(path.Path(), 0755); 206*a4bdd26dSAxel Dörfler if (status != B_OK) { 207*a4bdd26dSAxel Dörfler fprintf(stderr, "Could not create path %s: %s\n", path.Path(), 208*a4bdd26dSAxel Dörfler strerror(status)); 209*a4bdd26dSAxel Dörfler return NULL; 210*a4bdd26dSAxel Dörfler } 211*a4bdd26dSAxel Dörfler 212*a4bdd26dSAxel Dörfler entry_ref ref; 213*a4bdd26dSAxel Dörfler status = get_ref_for_path(path.Path(), &ref); 214*a4bdd26dSAxel Dörfler if (status != B_OK) { 215*a4bdd26dSAxel Dörfler fprintf(stderr, "Could not get ref for %s: %s\n", path.Path(), 216*a4bdd26dSAxel Dörfler strerror(status)); 217*a4bdd26dSAxel Dörfler return NULL; 218*a4bdd26dSAxel Dörfler } 219*a4bdd26dSAxel Dörfler 220*a4bdd26dSAxel Dörfler return new IMAPFolder(mailbox, ref); 221*a4bdd26dSAxel Dörfler } 222*a4bdd26dSAxel Dörfler 223*a4bdd26dSAxel Dörfler 224*a4bdd26dSAxel Dörfler status_t 225*a4bdd26dSAxel Dörfler IMAPProtocol::_CreateFolderChangeSemaphore() 226*a4bdd26dSAxel Dörfler { 227*a4bdd26dSAxel Dörfler fFolderChangeSemaphore = create_sem(0, "imap folder change"); 228*a4bdd26dSAxel Dörfler return fFolderChangeSemaphore < 0 ? fFolderChangeSemaphore : B_OK; 229*a4bdd26dSAxel Dörfler } 230*a4bdd26dSAxel Dörfler 231*a4bdd26dSAxel Dörfler 232186c96d5SAxel Dörfler // #pragma mark - 233186c96d5SAxel Dörfler 234186c96d5SAxel Dörfler 235186c96d5SAxel Dörfler extern "C" BInboundMailProtocol* 236186c96d5SAxel Dörfler instantiate_inbound_protocol(const BMailAccountSettings& settings) 237186c96d5SAxel Dörfler { 238186c96d5SAxel Dörfler return new IMAPProtocol(settings); 239186c96d5SAxel Dörfler } 240