IMAPIAdviseSink * MAPIStorageAdviser::_GetSink( CMAPIAdviseSink * pMapiNotifySink ) { ASSERT(pMapiNotifySink); IMAPIAdviseSink * pMapiSink = NULL; HRESULT hr = pMapiNotifySink->QueryInterface(IID_IMAPIAdviseSink, (void **)&pMapiSink); if(FAILED(hr)){ pMapiSink->Release(); return NULL; } return pMapiSink; }
/** * Opens an admin session and the outgoing queue. If either one * produces an error this function will return. If the queue is empty, * it will wait for a notification when new data is present in the * outgoing queue table. * * @param[in] szSMTP The SMTP server to send to. * @param[in] ulPort The SMTP port to sent to. * @param[in] szPath URI of Zarafa server to connect to, must be file:// or https:// with valid ssl certificates. * @return HRESULT */ HRESULT ProcessQueue(char* szSMTP, int ulPort, char *szPath) { HRESULT hr = hrSuccess; IMAPISession *lpAdminSession = NULL; IECSpooler *lpSpooler = NULL; IMAPITable *lpTable = NULL; IMAPIAdviseSink *lpAdviseSink = NULL; ULONG ulConnection = 0; SizedSPropTagArray(5, sOutgoingCols) = { 5, { PR_EC_MAILBOX_OWNER_ACCOUNT_W, PR_STORE_ENTRYID, PR_ENTRYID, PR_EC_OUTGOING_FLAGS, PR_DEFERRED_SEND_TIME, } }; SSortOrderSet sSort = { 1, 0, 0, { { PR_EC_HIERARCHYID, TABLE_SORT_ASCEND } } }; hr = HrOpenECAdminSession(g_lpLogger, &lpAdminSession, "zarafa-spooler:system", PROJECT_SVN_REV_STR, szPath, EC_PROFILE_FLAGS_NO_PUBLIC_STORE, g_lpConfig->GetSetting("sslkey_file", "", NULL), g_lpConfig->GetSetting("sslkey_pass", "", NULL)); if (hr != hrSuccess) { g_lpLogger->Log(EC_LOGLEVEL_ERROR, "Unable to open admin session. Error 0x%08X", hr); goto exit; } if (disconnects == 0) g_lpLogger->Log(EC_LOGLEVEL_DEBUG, "Connection to Zarafa server succeeded"); else g_lpLogger->Log(EC_LOGLEVEL_INFO, "Connection to Zarafa server succeeded after %d retries", disconnects); disconnects = 0; // first call succeeded, assume all is well. hr = GetAdminSpooler(lpAdminSession, &lpSpooler); if (hr != hrSuccess) { g_lpLogger->Log(EC_LOGLEVEL_ERROR, "ProcessQueue: GetAdminSpooler failed %x", hr); goto exit; } // Mark reload as done since we reloaded the outgoing table nReload = false; // Request the master outgoing table hr = lpSpooler->GetMasterOutgoingTable(0, &lpTable); if (hr != hrSuccess) { g_lpLogger->Log(EC_LOGLEVEL_ERROR, "Master outgoing queue not available"); goto exit; } hr = lpTable->SetColumns((LPSPropTagArray)&sOutgoingCols, 0); if (hr != hrSuccess) { g_lpLogger->Log(EC_LOGLEVEL_ERROR, "Unable to setColumns() on OutgoingQueue"); goto exit; } // Sort by ascending hierarchyid: first in, first out queue hr = lpTable->SortTable(&sSort, 0); if (hr != hrSuccess) { g_lpLogger->Log(EC_LOGLEVEL_ERROR, "Unable to SortTable() on OutgoingQueue"); goto exit; } hr = HrAllocAdviseSink(AdviseCallback, NULL, &lpAdviseSink); if (hr != hrSuccess) { g_lpLogger->Log(EC_LOGLEVEL_ERROR, "Unable to allocate memory for advise sink"); goto exit; } // notify on new mail in the outgoing table hr = lpTable->Advise(fnevTableModified, lpAdviseSink, &ulConnection); while(!bQuit && !nReload) { bMessagesWaiting = false; lpTable->SeekRow(BOOKMARK_BEGINNING, 0, NULL); // also checks not to send a message again which is already sending hr = ProcessAllEntries(lpAdminSession, lpSpooler, lpTable, szSMTP, ulPort, szPath); if(hr != hrSuccess) { g_lpLogger->Log(EC_LOGLEVEL_WARNING, "ProcessQueue: ProcessAllEntries failed %x", hr); goto exit; } // Exit signal, break the operation if(bQuit) break; if(nReload) break; pthread_mutex_lock(&hMutexMessagesWaiting); if(!bMessagesWaiting) { struct timespec timeout; struct timeval now; // Wait for max 60 sec, then run queue anyway gettimeofday(&now,NULL); timeout.tv_sec = now.tv_sec + 60; timeout.tv_nsec = now.tv_usec * 1000; while (!bMessagesWaiting) { if (pthread_cond_timedwait(&hCondMessagesWaiting, &hMutexMessagesWaiting, &timeout) == ETIMEDOUT || bMessagesWaiting || bQuit || nReload) break; // not timed out, no messages waiting, not quit requested, no table reload required: // we were triggered for a cleanup call. CleanFinishedMessages(lpAdminSession, lpSpooler); } } pthread_mutex_unlock(&hMutexMessagesWaiting); // remove any entries that were done during the wait CleanFinishedMessages(lpAdminSession, lpSpooler); } exit: // when we exit, we must make sure all forks started are cleaned if (bQuit) { ULONG ulCount = 0; ULONG ulThreads = 0; while (ulCount < 60) { if ((ulCount % 5) == 0) { ulThreads = mapSendData.size(); g_lpLogger->Log(EC_LOGLEVEL_WARNING, "Still waiting for %d thread%c to exit.", ulThreads, ulThreads!=1?'s':' '); } CleanFinishedMessages(lpAdminSession, lpSpooler); if (mapSendData.size() == 0) break; Sleep(1000); ulCount++; } if (ulCount == 60) g_lpLogger->Log(EC_LOGLEVEL_DEBUG, "%d threads did not yet exit, closing anyway.", (int)mapSendData.size()); } else if (nReload) { g_lpLogger->Log(EC_LOGLEVEL_WARNING, "Table reload requested, breaking server connection"); } if (lpTable && ulConnection) lpTable->Unadvise(ulConnection); if (lpAdviseSink) lpAdviseSink->Release(); if (lpTable) lpTable->Release(); if (lpSpooler) lpSpooler->Release(); if (lpAdminSession) lpAdminSession->Release(); return hr; }