示例#1
0
/*
 * add a message to the sending queue.
 * iLen = required size of the memory block to hold the message
 */
int SendQueue::addTo(TWindowData *dat, const int iLen, int dwFlags)
{
	int iLength = 0, i;
	int iFound = NR_SENDJOBS;

	if (m_currentIndex >= NR_SENDJOBS) {
		_DebugPopup(dat->hContact, _T("Send queue full"));
		return 0;
	}
	/*
	 * find a free entry in the send queue...
	 */
	for (i = 0; i < NR_SENDJOBS; i++) {
		if (m_jobs[i].hOwner != 0 || m_jobs[i].iStatus != 0) {
			// this entry is used, check if it's orphaned and can be removed...
			if (m_jobs[i].hwndOwner && IsWindow(m_jobs[i].hwndOwner))           // window exists, do not reuse it
				continue;
			if (time(NULL) - m_jobs[i].dwTime < 120)                              // non-acked entry, but not old enough, don't re-use it
				continue;
			clearJob(i);
			iFound = i;
			goto entry_found;
		}
		iFound = i;
		break;
	}
entry_found:
	if (iFound == NR_SENDJOBS) {
		_DebugPopup(dat->hContact, _T("Send queue full"));
		return 0;
	}
	iLength = iLen;
	if (iLength > 0) {
		if (m_jobs[iFound].sendBuffer == NULL) {
			if (iLength < HISTORY_INITIAL_ALLOCSIZE)
				iLength = HISTORY_INITIAL_ALLOCSIZE;
			m_jobs[iFound].sendBuffer = (char *)malloc(iLength);
			m_jobs[iFound].dwLen = iLength;
		}
		else {
			if (iLength > m_jobs[iFound].dwLen) {
				m_jobs[iFound].sendBuffer = (char *)realloc(m_jobs[iFound].sendBuffer, iLength);
				m_jobs[iFound].dwLen = iLength;
			}
		}
		CopyMemory(m_jobs[iFound].sendBuffer, dat->sendBuffer, iLen);
	}
	m_jobs[iFound].dwFlags = dwFlags;
	m_jobs[iFound].dwTime = time(NULL);

	HWND	hwndDlg = dat->hwnd;

	dat->cache->saveHistory(0, 0);
	::SetDlgItemText(hwndDlg, IDC_MESSAGE, _T(""));
	::SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));

	UpdateSaveAndSendButton(dat);
	sendQueued(dat, iFound);
	return 0;
}
示例#2
0
void  xWorkingThread::exitThread(bool bWaited)
{
	if(m_pRunner == NULL)
		return ;

	xThreadProc::exitThread(bWaited);
	clearJob();

	m_pRunner->KillObject();
	m_pRunner = NULL;
	return ;
}
示例#3
0
int SendQueue::addTo(TWindowData *dat, size_t iLen, int dwFlags)
{
	int i;
	int iFound = NR_SENDJOBS;

	if (m_currentIndex >= NR_SENDJOBS) {
		_DebugPopup(dat->hContact, _T("Send queue full"));
		return 0;
	}

	// find a mir_free entry in the send queue...
	for (i = 0; i < NR_SENDJOBS; i++) {
		if (m_jobs[i].hContact != 0 || m_jobs[i].iStatus != 0) {
			// this entry is used, check if it's orphaned and can be removed...
			if (m_jobs[i].hOwnerWnd && IsWindow(m_jobs[i].hOwnerWnd)) // window exists, do not reuse it
				continue;
			if (time(NULL) - m_jobs[i].dwTime < 120) // non-acked entry, but not old enough, don't re-use it
				continue;
			clearJob(i);
			iFound = i;
			goto entry_found;
		}
		iFound = i;
		break;
	}
entry_found:
	if (iFound == NR_SENDJOBS) {
		_DebugPopup(dat->hContact, _T("Send queue full"));
		return 0;
	}

	SendJob &job = m_jobs[iFound];
	job.szSendBuffer = (char*)mir_alloc(iLen);
	memcpy(job.szSendBuffer, dat->sendBuffer, iLen);

	job.dwFlags = dwFlags;
	job.dwTime = time(NULL);

	HWND	hwndDlg = dat->hwnd;

	dat->cache->saveHistory(0, 0);
	::SetDlgItemText(hwndDlg, IDC_MESSAGE, _T(""));
	::SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGE));

	UpdateSaveAndSendButton(dat);
	sendQueued(dat, iFound);
	return 0;
}
示例#4
0
TransferManagerWindow::TransferManagerWindow(QXmppTransferManager *transferManager, QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::TransferManagerWindow),
    m_transferManager(transferManager)
{
    ui->setupUi(this);
    m_transferManagerModel = new TransferManagerModel(this);
    ui->tableView->setModel(m_transferManagerModel);
    ui->tableView->horizontalHeader()->setStretchLastSection(true);
    ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
    ui->tableView->setAlternatingRowColors(true);
    connect(ui->actionStopTransfer, SIGNAL(triggered()),
            this, SLOT(stopTransferJob()) );
    connect(ui->actionCleanList, SIGNAL(triggered()),
            m_transferManagerModel, SLOT(clearJob()) );

    ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(ui->tableView, SIGNAL(customContextMenuRequested(const QPoint &)),
            this, SLOT(showCustomContextMenu(const QPoint &)) );
    setAttribute(Qt::WA_QuitOnClose, false);
}
示例#5
0
int SendQueue::ackMessage(TWindowData *dat, WPARAM wParam, LPARAM lParam)
{
	ACKDATA				*ack = (ACKDATA *) lParam;
	DBEVENTINFO			dbei = { 0};
	HANDLE				hNewEvent;
	int					iFound = SendQueue::NR_SENDJOBS, iNextFailed;
	TContainerData *m_pContainer = 0;
	if (dat)
		m_pContainer = dat->pContainer;

	iFound = (int)(LOWORD(wParam));
	//i = (int)(HIWORD(wParam));

	if (m_jobs[iFound].iStatus == SQ_ERROR) {      // received ack for a job which is already in error state...
		if (dat) {                        // window still open
			if (dat->iCurrentQueueError == iFound) {
				dat->iCurrentQueueError = -1;
				showErrorControls(dat, FALSE);
			}
		}
		/*
		 * we must discard this job, because there is no message window open to handle the
		 * error properly. But we display a tray notification to inform the user about the problem.
		 */
		else
			goto inform_and_discard;
	}

	// failed acks are only handled when the window is still open. with no window open, they will be *silently* discarded

	if (ack->result == ACKRESULT_FAILED) {
		if (dat) {
			/*
			 * "hard" errors are handled differently in multisend. There is no option to retry - once failed, they
			 * are discarded and the user is notified with a small log message.
			 */
			if (!nen_options.iNoSounds && !(m_pContainer->dwFlags & CNT_NOSOUND))
				SkinPlaySound("SendError");

			TCHAR *szAckMsg = mir_a2t((char *)ack->lParam);
			mir_sntprintf(m_jobs[iFound].szErrorMsg, safe_sizeof(m_jobs[iFound].szErrorMsg),
						 CTranslator::get(CTranslator::GEN_MSG_DELIVERYFAILURE), szAckMsg);
			m_jobs[iFound].iStatus = SQ_ERROR;
			mir_free(szAckMsg);
			KillTimer(dat->hwnd, TIMERID_MSGSEND + iFound);
			if (!(dat->dwFlags & MWF_ERRORSTATE))
				handleError(dat, iFound);
			return 0;
		}
		else {
inform_and_discard:
			_DebugPopup(m_jobs[iFound].hOwner, CTranslator::get(CTranslator::GEN_SQ_DELIVERYFAILEDLATE));
			clearJob(iFound);
			return 0;
		}
	}

	dbei.cbSize = sizeof(dbei);
	dbei.eventType = EVENTTYPE_MESSAGE;
	dbei.flags = DBEF_SENT;
	dbei.szModule = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) m_jobs[iFound].hOwner, 0);
	dbei.timestamp = time(NULL);
	dbei.cbBlob = lstrlenA(m_jobs[iFound].sendBuffer) + 1;

	if (dat)
		dat->cache->updateStats(TSessionStats::BYTES_SENT, dbei.cbBlob - 1);
	else {
		CContactCache *c = CContactCache::getContactCache(m_jobs[iFound].hOwner);
		if(c)
			c->updateStats(TSessionStats::BYTES_SENT, dbei.cbBlob - 1);
	}

	if (m_jobs[iFound].dwFlags & PREF_UNICODE)
		dbei.cbBlob *= sizeof(TCHAR) + 1;
	if (m_jobs[iFound].dwFlags & PREF_RTL)
		dbei.flags |= DBEF_RTL;
	if (m_jobs[iFound].dwFlags & PREF_UTF)
		dbei.flags |= DBEF_UTF;
	dbei.pBlob = (PBYTE) m_jobs[iFound].sendBuffer;
	hNewEvent = (HANDLE) CallService(MS_DB_EVENT_ADD, (WPARAM) m_jobs[iFound].hOwner, (LPARAM) & dbei);

	if (m_pContainer) {
		if (!nen_options.iNoSounds && !(m_pContainer->dwFlags & CNT_NOSOUND))
			SkinPlaySound("SendMsg");
	}

	if (dat && (m_jobs[iFound].hOwner == dat->hContact)) {
		if (dat->hDbEventFirst == NULL) {
			dat->hDbEventFirst = hNewEvent;
			SendMessage(dat->hwnd, DM_REMAKELOG, 0, 0);
		}
	}

	m_jobs[iFound].hSendId = NULL;
	m_jobs[iFound].iAcksNeeded--;

	if (m_jobs[iFound].iAcksNeeded == 0) {              // everything sent
		//if (m_jobs[iFound].hOwner != 0 && dat)
		//	EnableSending(dat, TRUE);
		clearJob(iFound);
		if (dat) {
			KillTimer(dat->hwnd, TIMERID_MSGSEND + iFound);
			dat->iOpenJobs--;
		}
		m_currentIndex--;
	}
	if (dat) {
		checkQueue(dat);
		if ((iNextFailed = findNextFailed(dat)) >= 0 && !(dat->dwFlags & MWF_ERRORSTATE))
			handleError(dat, iNextFailed);
		//MAD: close on send mode
		else {
			if (M->GetByte("AutoClose", 0)) {
				if(M->GetByte("adv_AutoClose_2", 0))
					SendMessage(dat->hwnd, WM_CLOSE, 0, 1);
				else
					SendMessage(dat->pContainer->hwnd, WM_CLOSE, 0, 0);
			}
		}
		//MAD_
	}
	return 0;
}
示例#6
0
int SendQueue::sendQueued(TWindowData *dat, const int iEntry)
{
	HWND	hwndDlg = dat->hwnd;

	if (dat->sendMode & SMODE_MULTIPLE) {
		HANDLE			hContact, hItem;
		int				iJobs = 0;
		int				iMinLength = 0;
		CContactCache*	c = 0;

		hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);

		m_jobs[iEntry].hOwner = dat->hContact;
		m_jobs[iEntry].iStatus = SQ_INPROGRESS;
		m_jobs[iEntry].hwndOwner = hwndDlg;

		int	iSendLength = getSendLength(iEntry, dat->sendMode);

		do {
			hItem = (HANDLE) SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_FINDCONTACT, (WPARAM) hContact, 0);
			if (hItem && SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_GETCHECKMARK, (WPARAM) hItem, 0)) {
				c = CContactCache::getContactCache(hContact);
				if(c)
					iMinLength = (iMinLength == 0 ? c->getMaxMessageLength() : min(c->getMaxMessageLength(), iMinLength));
			}
		} while (hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0));

		if(iSendLength >= iMinLength) {
			TCHAR	tszError[256];

			mir_sntprintf(tszError, 256, CTranslator::get(CTranslator::GEN_SQ_SENDLATER_ERROR_MSG_TOO_LONG), iMinLength);
			::SendMessage(dat->hwnd, DM_ACTIVATETOOLTIP, IDC_MESSAGE, reinterpret_cast<LPARAM>(tszError));
			sendQueue->clearJob(iEntry);
			return(0);
		}

		hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
		do {
			hItem = (HANDLE) SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_FINDCONTACT, (WPARAM) hContact, 0);
			if (hItem && SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_GETCHECKMARK, (WPARAM) hItem, 0)) {
				doSendLater(iEntry, 0, hContact, false);
				iJobs++;
			}
		} while (hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0));

		sendQueue->clearJob(iEntry);
		if(iJobs)
			sendLater->flushQueue();							// force queue processing
		return(0);
	}
	else {
		if (dat->hContact == NULL)
			return 0;  //never happens

		dat->nMax = dat->cache->getMaxMessageLength();                      // refresh length info

		if (dat->sendMode & SMODE_FORCEANSI && M->GetByte(dat->cache->getActiveContact(), dat->cache->getActiveProto(), "UnicodeSend", 1))
			M->WriteByte(dat->cache->getActiveContact(), dat->cache->getActiveProto(), "UnicodeSend", 0);
		else if (!(dat->sendMode & SMODE_FORCEANSI) && !M->GetByte(dat->cache->getActiveContact(), dat->cache->getActiveProto(), "UnicodeSend", 0))
			M->WriteByte(dat->cache->getActiveContact(), dat->cache->getActiveProto(), "UnicodeSend", 1);

		if (M->GetByte("autosplit", 1) && !(dat->sendMode & SMODE_SENDLATER)) {
			BOOL    fSplit = FALSE;
			DWORD   dwOldFlags;

			/*
			 * determine send buffer length
			 */
			if(getSendLength(iEntry, dat->sendMode) >= dat->nMax)
				fSplit = true;

			if (!fSplit)
				goto send_unsplitted;

			m_jobs[iEntry].hOwner = dat->hContact;
			m_jobs[iEntry].hwndOwner = hwndDlg;
			m_jobs[iEntry].iStatus = SQ_INPROGRESS;
			m_jobs[iEntry].iAcksNeeded = 1;
			m_jobs[iEntry].chunkSize = dat->nMax;

			dwOldFlags = m_jobs[iEntry].dwFlags;
			if (dat->sendMode & SMODE_FORCEANSI)
				m_jobs[iEntry].dwFlags &= ~PREF_UNICODE;

			if (!(m_jobs[iEntry].dwFlags & PREF_UNICODE) || dat->sendMode & SMODE_FORCEANSI)
				mir_forkthread(DoSplitSendA, (LPVOID)iEntry);
			else
				mir_forkthread(DoSplitSendW, (LPVOID)iEntry);
			m_jobs[iEntry].dwFlags = dwOldFlags;
		}
		else {

send_unsplitted:

			m_jobs[iEntry].hOwner = dat->hContact;
			m_jobs[iEntry].hwndOwner = hwndDlg;
			m_jobs[iEntry].iStatus = SQ_INPROGRESS;
			m_jobs[iEntry].iAcksNeeded = 1;
			if(dat->sendMode & SMODE_SENDLATER) {
				TCHAR	tszError[256];

				int iSendLength = getSendLength(iEntry, dat->sendMode);
				if(iSendLength >= dat->nMax) {
					mir_sntprintf(tszError, 256, CTranslator::get(CTranslator::GEN_SQ_SENDLATER_ERROR_MSG_TOO_LONG), dat->nMax);
					SendMessage(dat->hwnd, DM_ACTIVATETOOLTIP, IDC_MESSAGE, reinterpret_cast<LPARAM>(tszError));
					clearJob(iEntry);
					return(0);
				}
				doSendLater(iEntry, dat);
				clearJob(iEntry);
				return(0);
			}
			m_jobs[iEntry].hSendId = (HANDLE) CallContactService(dat->hContact, MsgServiceName(dat->hContact, dat, m_jobs[iEntry].dwFlags), (dat->sendMode & SMODE_FORCEANSI) ? (m_jobs[iEntry].dwFlags & ~PREF_UNICODE) : m_jobs[iEntry].dwFlags, (LPARAM) m_jobs[iEntry].sendBuffer);

			if (dat->sendMode & SMODE_NOACK) {              // fake the ack if we are not interested in receiving real acks
				ACKDATA ack = {0};
				ack.hContact = dat->hContact;
				ack.hProcess = m_jobs[iEntry].hSendId;
				ack.type = ACKTYPE_MESSAGE;
				ack.result = ACKRESULT_SUCCESS;
				SendMessage(hwndDlg, HM_EVENTSENT, (WPARAM)MAKELONG(iEntry, 0), (LPARAM)&ack);
			}
			else
				SetTimer(hwndDlg, TIMERID_MSGSEND + iEntry, PluginConfig.m_MsgTimeout, NULL);
		}
	}
	dat->iOpenJobs++;
	m_currentIndex++;

	// give icon feedback...

	if (dat->pContainer->hwndActive == hwndDlg)
		::UpdateReadChars(dat);

	if (!(dat->sendMode & SMODE_NOACK))
		::HandleIconFeedback(dat, PluginConfig.g_IconSend);

	if (M->GetByte(SRMSGSET_AUTOMIN, SRMSGDEFSET_AUTOMIN))
		::SendMessage(dat->pContainer->hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
	return 0;
}
示例#7
0
void xWorkingThreadPool::uninit()
{
	clearJob();
	if(m_pQueueLocker) m_pQueueLocker->KillObject();
}
示例#8
0
int SendQueue::ackMessage(TWindowData *dat, WPARAM wParam, LPARAM lParam)
{
	ACKDATA *ack = (ACKDATA *)lParam;

	TContainerData *m_pContainer = 0;
	if (dat)
		m_pContainer = dat->pContainer;

	int iFound = (int)(LOWORD(wParam));
	SendJob &job = m_jobs[iFound];

	if (job.iStatus == SQ_ERROR) { // received ack for a job which is already in error state...
		if (dat) {                  // window still open
			if (dat->iCurrentQueueError == iFound) {
				dat->iCurrentQueueError = -1;
				showErrorControls(dat, FALSE);
			}
		}
		// we must discard this job, because there is no message window open to handle the
		// error properly. But we display a tray notification to inform the user about the problem.
		else goto inform_and_discard;
	}

	// failed acks are only handled when the window is still open. with no window open, they will be *silently* discarded

	if (ack->result == ACKRESULT_FAILED) {
		if (dat) {
			// "hard" errors are handled differently in multisend. There is no option to retry - once failed, they
			// are discarded and the user is notified with a small log message.
			if (!nen_options.iNoSounds && !(m_pContainer->dwFlags & CNT_NOSOUND))
				SkinPlaySound("SendError");

			TCHAR *szAckMsg = mir_a2t((char *)ack->lParam);
			mir_sntprintf(job.szErrorMsg, TranslateT("Delivery failure: %s"), szAckMsg);
			job.iStatus = SQ_ERROR;
			mir_free(szAckMsg);
			KillTimer(dat->hwnd, TIMERID_MSGSEND + iFound);
			if (!(dat->dwFlags & MWF_ERRORSTATE))
				handleError(dat, iFound);
			return 0;
		}

	inform_and_discard:
		_DebugPopup(job.hContact, TranslateT("A message delivery has failed after the contacts chat window was closed. You may want to resend the last message"));
		clearJob(iFound);
		return 0;
	}

	DBEVENTINFO dbei = { sizeof(dbei) };
	dbei.eventType = EVENTTYPE_MESSAGE;
	dbei.flags = DBEF_SENT;
	dbei.szModule = GetContactProto(job.hContact);
	dbei.timestamp = time(NULL);
	dbei.cbBlob = (int)mir_strlen(job.szSendBuffer) + 1;

	if (dat)
		dat->cache->updateStats(TSessionStats::BYTES_SENT, dbei.cbBlob - 1);
	else {
		CContactCache *cc = CContactCache::getContactCache(job.hContact);
		if (cc)
			cc->updateStats(TSessionStats::BYTES_SENT, dbei.cbBlob - 1);
	}

	if (job.dwFlags & PREF_RTL)
		dbei.flags |= DBEF_RTL;
	dbei.flags |= DBEF_UTF;
	dbei.pBlob = (PBYTE)job.szSendBuffer;

	MessageWindowEvent evt = { sizeof(evt), (INT_PTR)job.hSendId, job.hContact, &dbei };
	NotifyEventHooks(PluginConfig.m_event_WriteEvent, 0, (LPARAM)&evt);

	job.szSendBuffer = (char*)dbei.pBlob;
	MEVENT hNewEvent = db_event_add(job.hContact, &dbei);

	if (m_pContainer)
		if (!nen_options.iNoSounds && !(m_pContainer->dwFlags & CNT_NOSOUND))
			SkinPlaySound("SendMsg");

	M.BroadcastMessage(DM_APPENDMCEVENT, job.hContact, LPARAM(hNewEvent));

	job.hSendId = NULL;
	job.iAcksNeeded--;

	if (job.iAcksNeeded == 0) {              // everything sent
		clearJob(iFound);
		if (dat) {
			KillTimer(dat->hwnd, TIMERID_MSGSEND + iFound);
			dat->iOpenJobs--;
		}
		m_currentIndex--;
	}
	if (dat) {
		checkQueue(dat);

		int iNextFailed = findNextFailed(dat);
		if (iNextFailed >= 0 && !(dat->dwFlags & MWF_ERRORSTATE))
			handleError(dat, iNextFailed);
		else {
			if (M.GetByte("AutoClose", 0)) {
				if (M.GetByte("adv_AutoClose_2", 0))
					SendMessage(dat->hwnd, WM_CLOSE, 0, 1);
				else
					SendMessage(dat->pContainer->hwnd, WM_CLOSE, 0, 0);
			}
		}
	}
	return 0;
}
示例#9
0
int SendQueue::sendQueued(TWindowData *dat, const int iEntry)
{
	CContactCache *ccActive = CContactCache::getContactCache(dat->hContact);
	if (ccActive == NULL)
		return 0;

	HWND	hwndDlg = dat->hwnd;

	if (dat->sendMode & SMODE_MULTIPLE) {
		int iJobs = 0;
		int iMinLength = 0;

		m_jobs[iEntry].iStatus = SQ_INPROGRESS;
		m_jobs[iEntry].hContact = ccActive->getActiveContact();
		m_jobs[iEntry].hOwnerWnd = hwndDlg;

		size_t iSendLength = getSendLength(iEntry);

		for (MCONTACT hContact = db_find_first(); hContact; hContact = db_find_next(hContact)) {
			HANDLE hItem = (HANDLE)SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_FINDCONTACT, hContact, 0);
			if (hItem && SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_GETCHECKMARK, (WPARAM)hItem, 0)) {
				CContactCache *c = CContactCache::getContactCache(hContact);
				if (c)
					iMinLength = (iMinLength == 0 ? c->getMaxMessageLength() : min(c->getMaxMessageLength(), iMinLength));
			}
		}

		if (iSendLength >= iMinLength) {
			TCHAR	tszError[256];
			mir_sntprintf(tszError, TranslateT("The message cannot be sent delayed or to multiple contacts, because it exceeds the maximum allowed message length of %d bytes"), iMinLength);
			::SendMessage(dat->hwnd, DM_ACTIVATETOOLTIP, IDC_MESSAGE, LPARAM(tszError));
			sendQueue->clearJob(iEntry);
			return 0;
		}

		for (MCONTACT hContact = db_find_first(); hContact; hContact = db_find_next(hContact)) {
			HANDLE hItem = (HANDLE)SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_FINDCONTACT, hContact, 0);
			if (hItem && SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_GETCHECKMARK, (WPARAM)hItem, 0)) {
				doSendLater(iEntry, 0, hContact, false);
				iJobs++;
			}
		}

		sendQueue->clearJob(iEntry);
		if (iJobs)
			sendLater->flushQueue(); // force queue processing
		return 0;
	}

	if (dat->hContact == NULL)
		return 0;  //never happens

	dat->nMax = dat->cache->getMaxMessageLength(); // refresh length info

	if (M.GetByte("autosplit", 0) && !(dat->sendMode & SMODE_SENDLATER)) {
		// determine send buffer length
		BOOL fSplit = FALSE;
		if (getSendLength(iEntry) >= dat->nMax)
			fSplit = true;

		if (!fSplit)
			goto send_unsplitted;

		m_jobs[iEntry].hContact = ccActive->getActiveContact();
		m_jobs[iEntry].hOwnerWnd = hwndDlg;
		m_jobs[iEntry].iStatus = SQ_INPROGRESS;
		m_jobs[iEntry].iAcksNeeded = 1;
		m_jobs[iEntry].chunkSize = dat->nMax;

		DWORD dwOldFlags = m_jobs[iEntry].dwFlags;
		mir_forkthread(DoSplitSendA, (LPVOID)iEntry);
		m_jobs[iEntry].dwFlags = dwOldFlags;
	}
	else {
	send_unsplitted:
		m_jobs[iEntry].hContact = ccActive->getActiveContact();
		m_jobs[iEntry].hOwnerWnd = hwndDlg;
		m_jobs[iEntry].iStatus = SQ_INPROGRESS;
		m_jobs[iEntry].iAcksNeeded = 1;
		if (dat->sendMode & SMODE_SENDLATER) {
			TCHAR	tszError[256];

			size_t iSendLength = getSendLength(iEntry);
			if (iSendLength >= dat->nMax) {
				mir_sntprintf(tszError, TranslateT("The message cannot be sent delayed or to multiple contacts, because it exceeds the maximum allowed message length of %d bytes"), dat->nMax);
				SendMessage(dat->hwnd, DM_ACTIVATETOOLTIP, IDC_MESSAGE, LPARAM(tszError));
				clearJob(iEntry);
				return 0;
			}
			doSendLater(iEntry, dat);
			clearJob(iEntry);
			return 0;
		}
		m_jobs[iEntry].hSendId = (HANDLE)CallContactService(dat->hContact, PSS_MESSAGE, m_jobs[iEntry].dwFlags, (LPARAM)m_jobs[iEntry].szSendBuffer);

		if (dat->sendMode & SMODE_NOACK) {              // fake the ack if we are not interested in receiving real acks
			ACKDATA ack = { 0 };
			ack.hContact = dat->hContact;
			ack.hProcess = m_jobs[iEntry].hSendId;
			ack.type = ACKTYPE_MESSAGE;
			ack.result = ACKRESULT_SUCCESS;
			SendMessage(hwndDlg, HM_EVENTSENT, (WPARAM)MAKELONG(iEntry, 0), (LPARAM)&ack);
		}
		else SetTimer(hwndDlg, TIMERID_MSGSEND + iEntry, PluginConfig.m_MsgTimeout, NULL);
	}

	dat->iOpenJobs++;
	m_currentIndex++;

	// give icon feedback...
	if (dat->pContainer->hwndActive == hwndDlg)
		::UpdateReadChars(dat);

	if (!(dat->sendMode & SMODE_NOACK))
		::HandleIconFeedback(dat, PluginConfig.g_IconSend);

	if (M.GetByte(SRMSGSET_AUTOMIN, SRMSGDEFSET_AUTOMIN))
		::SendMessage(dat->pContainer->hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
	return 0;
}