+eNextState POP3C_ReadQuitState(pop3aggr *RecvMsg)
+{
+ AsyncIO *IO = &RecvMsg->IO;
+ POP3C_DBG_READ();
+ return eTerminateConnection;
+}
+
+const long POP3_C_ConnTimeout = 1000;
+const long DefaultPOP3Port = 110;
+
+Pop3ClientHandler POP3C_ReadHandlers[] = {
+ POP3C_ReadGreeting,
+ POP3C_GetUserState,
+ POP3C_GetPassState,
+ POP3C_GetListCommandState,
+ POP3C_GetListOneLine,
+ POP3C_GetOneMessageIDState,
+ POP3C_ReadMessageBodyFollowing,
+ POP3C_ReadMessageBody,
+ POP3C_ReadDeleteState,
+ POP3C_ReadQuitState,
+};
+
+const long POP3_C_SendTimeouts[POP3C_MaxRead] = {
+ 100,
+ 100,
+ 100,
+ 100,
+ 100,
+ 100,
+ 100,
+ 100
+};
+const ConstStr POP3C_ReadErrors[POP3C_MaxRead] = {
+ {HKEY("Connection broken during ")},
+ {HKEY("Connection broken during ")},
+ {HKEY("Connection broken during ")},
+ {HKEY("Connection broken during ")},
+ {HKEY("Connection broken during ")},
+ {HKEY("Connection broken during ")},
+ {HKEY("Connection broken during ")},
+ {HKEY("Connection broken during ")}
+};
+
+Pop3ClientHandler POP3C_SendHandlers[] = {
+ NULL, /* we don't send a greeting */
+ POP3C_SendUser,
+ POP3C_SendPassword,
+ POP3C_SendListCommand,
+ NULL,
+ POP3C_GetOneMessagID,
+ POP3C_SendGetOneMsg,
+ NULL,
+ POP3C_SendDelete,
+ POP3C_SendQuit
+};
+
+const long POP3_C_ReadTimeouts[] = {
+ 100,
+ 100,
+ 100,
+ 100,
+ 100,
+ 100,
+ 100,
+ 100,
+ 100,
+ 100
+};
+/*****************************************************************************/
+/* POP3 CLIENT DISPATCHER */
+/*****************************************************************************/
+
+void POP3SetTimeout(eNextState NextTCPState, pop3aggr *pMsg)
+{
+ AsyncIO *IO = &pMsg->IO;
+ double Timeout = 0.0;
+
+ EVP3C_syslog(LOG_DEBUG, "POP3: %s\n", __FUNCTION__);
+
+ switch (NextTCPState) {
+ case eSendFile:
+ case eSendReply:
+ case eSendMore:
+ Timeout = POP3_C_SendTimeouts[pMsg->State];
+/*
+ if (pMsg->State == eDATABody) {
+ / * if we're sending a huge message, we need more time. * /
+ Timeout += StrLength(pMsg->msgtext) / 1024;
+ }
+*/
+ break;
+ case eReadFile:
+ case eReadMessage:
+ Timeout = POP3_C_ReadTimeouts[pMsg->State];
+/*
+ if (pMsg->State == eDATATerminateBody) {
+ / *
+ * some mailservers take a nap before accepting the message
+ * content inspection and such.
+ * /
+ Timeout += StrLength(pMsg->msgtext) / 1024;
+ }
+*/
+ break;
+ case eReadPayload:
+ Timeout = 100000;
+ /* TODO!!! */
+ break;
+ case eSendDNSQuery:
+ case eReadDNSReply:
+ case eConnect:
+ case eTerminateConnection:
+ case eDBQuery:
+ case eAbort:
+ case eReadMore://// TODO
+ return;
+ }
+ SetNextTimeout(&pMsg->IO, Timeout);
+}
+eNextState POP3_C_DispatchReadDone(AsyncIO *IO)
+{
+/* EVP3CCS_syslog(LOG_DEBUG, "POP3: %s\n", __FUNCTION__); to noisy anyways. */
+ pop3aggr *pMsg = IO->Data;
+ eNextState rc;
+
+ rc = POP3C_ReadHandlers[pMsg->State](pMsg);
+ if (rc != eReadMore)
+ pMsg->State++;
+ POP3SetTimeout(rc, pMsg);
+ return rc;
+}
+eNextState POP3_C_DispatchWriteDone(AsyncIO *IO)
+{
+ pop3aggr *pMsg = IO->Data;
+ eNextState rc;
+
+/* EVP3CCS_syslog(LOG_DEBUG, "POP3: %s\n", __FUNCTION__); to noisy anyways. */
+ rc = POP3C_SendHandlers[pMsg->State](pMsg);
+ POP3SetTimeout(rc, pMsg);
+ return rc;
+}
+
+
+/*****************************************************************************/
+/* POP3 CLIENT ERROR CATCHERS */
+/*****************************************************************************/
+eNextState POP3_C_Terminate(AsyncIO *IO)
+{
+/// pop3aggr *pMsg = (pop3aggr *)IO->Data;
+
+ EVP3CCS_syslog(LOG_DEBUG, "POP3: %s\n", __FUNCTION__);
+ FinalizePOP3AggrRun(IO);
+ return eAbort;
+}
+eNextState POP3_C_TerminateDB(AsyncIO *IO)
+{
+/// pop3aggr *pMsg = (pop3aggr *)IO->Data;
+
+ EVP3CCS_syslog(LOG_DEBUG, "POP3: %s\n", __FUNCTION__);
+ FinalizePOP3AggrRun(IO);
+ return eAbort;
+}
+eNextState POP3_C_Timeout(AsyncIO *IO)
+{
+ pop3aggr *pMsg = IO->Data;
+
+ EVP3CCS_syslog(LOG_DEBUG, "POP3: %s\n", __FUNCTION__);
+ StrBufPlain(IO->ErrMsg, CKEY(POP3C_ReadErrors[pMsg->State]));
+ return FailAggregationRun(IO);
+}
+eNextState POP3_C_ConnFail(AsyncIO *IO)
+{
+ pop3aggr *pMsg = (pop3aggr *)IO->Data;
+
+ EVP3CCS_syslog(LOG_DEBUG, "POP3: %s\n", __FUNCTION__);
+ StrBufPlain(IO->ErrMsg, CKEY(POP3C_ReadErrors[pMsg->State]));
+ return FailAggregationRun(IO);
+}
+eNextState POP3_C_DNSFail(AsyncIO *IO)
+{
+ pop3aggr *pMsg = (pop3aggr *)IO->Data;
+
+ EVP3CCS_syslog(LOG_DEBUG, "POP3: %s\n", __FUNCTION__);
+ StrBufPlain(IO->ErrMsg, CKEY(POP3C_ReadErrors[pMsg->State]));
+ return FailAggregationRun(IO);
+}
+eNextState POP3_C_Shutdown(AsyncIO *IO)
+{
+ EVP3CCS_syslog(LOG_DEBUG, "POP3: %s\n", __FUNCTION__);
+//// pop3aggr *pMsg = IO->Data;
+
+////pMsg->MyQEntry->Status = 3;
+///StrBufPlain(pMsg->MyQEntry->StatusMessage, HKEY("server shutdown during message retrieval."));
+ FinalizePOP3AggrRun(IO);
+ return eAbort;
+}
+
+
+/**
+ * @brief lineread Handler; understands when to read more POP3 lines,
+ * and when this is a one-lined reply.
+ */
+eReadState POP3_C_ReadServerStatus(AsyncIO *IO)
+{
+ eReadState Finished = eBufferNotEmpty;
+
+ switch (IO->NextState) {
+ case eSendDNSQuery:
+ case eReadDNSReply:
+ case eDBQuery:
+ case eConnect:
+ case eTerminateConnection:
+ case eAbort:
+ Finished = eReadFail;
+ break;
+ case eSendFile:
+ case eSendReply:
+ case eSendMore:
+ case eReadMore:
+ case eReadMessage:
+ Finished = StrBufChunkSipLine(IO->IOBuf, &IO->RecvBuf);
+ break;
+ case eReadFile:
+ case eReadPayload:
+ Finished = CtdlReadMessageBodyAsync(IO);
+ break;
+ }
+ return Finished;
+}
+
+/*****************************************************************************
+ * So we connect our Server IP here. *
+ *****************************************************************************/
+eNextState POP3_C_ReAttachToFetchMessages(AsyncIO *IO)
+{
+ pop3aggr *cpptr = IO->Data;
+
+ EVP3CCS_syslog(LOG_DEBUG, "POP3: %s\n", __FUNCTION__);
+////??? cpptr->State ++;
+ if (cpptr->Pos == NULL)
+ cpptr->Pos = GetNewHashPos(cpptr->MsgNumbers, 0);
+
+ POP3_C_DispatchWriteDone(IO);
+ ReAttachIO(IO, cpptr, 0);
+ IO->NextState = eReadMessage;
+ return IO->NextState;
+}
+
+eNextState pop3_connect_ip(AsyncIO *IO)
+{
+ pop3aggr *cpptr = IO->Data;
+
+ if (cpptr->IOStart == 0.0) /* whith or without DNS? */
+ cpptr->IOStart = IO->Now;
+
+ EVP3CCS_syslog(LOG_DEBUG, "POP3: %s\n", __FUNCTION__);
+
+ return EvConnectSock(IO,
+ POP3_C_ConnTimeout,
+ POP3_C_ReadTimeouts[0],
+ 1);
+}
+
+eNextState pop3_get_one_host_ip_done(AsyncIO *IO)
+{
+ pop3aggr *cpptr = IO->Data;
+ struct hostent *hostent;
+
+ QueryCbDone(IO);
+
+ hostent = cpptr->HostLookup.VParsedDNSReply;
+ if ((cpptr->HostLookup.DNSStatus == ARES_SUCCESS) &&
+ (hostent != NULL) ) {
+ memset(&cpptr->IO.ConnectMe->Addr, 0, sizeof(struct in6_addr));
+ if (cpptr->IO.ConnectMe->IPv6) {
+ memcpy(&cpptr->IO.ConnectMe->Addr.sin6_addr.s6_addr,
+ &hostent->h_addr_list[0],
+ sizeof(struct in6_addr));
+
+ cpptr->IO.ConnectMe->Addr.sin6_family =
+ hostent->h_addrtype;
+ cpptr->IO.ConnectMe->Addr.sin6_port =
+ htons(DefaultPOP3Port);
+ }
+ else {
+ struct sockaddr_in *addr =
+ (struct sockaddr_in*)
+ &cpptr->IO.ConnectMe->Addr;
+
+ memcpy(&addr->sin_addr.s_addr,
+ hostent->h_addr_list[0],
+ sizeof(uint32_t));
+
+ addr->sin_family = hostent->h_addrtype;
+ addr->sin_port = htons(DefaultPOP3Port);
+ }
+ return pop3_connect_ip(IO);
+ }
+ else
+ return eAbort;
+}
+
+eNextState pop3_get_one_host_ip(AsyncIO *IO)
+{
+ pop3aggr *cpptr = IO->Data;
+
+ cpptr->IOStart = IO->Now;
+
+ EVP3CCS_syslog(LOG_DEBUG, "POP3: %s\n", __FUNCTION__);
+
+ EVP3CCS_syslog(LOG_DEBUG,
+ "POP3 client[%ld]: looking up %s-Record %s : %d ...\n",
+ cpptr->n,
+ (cpptr->IO.ConnectMe->IPv6)? "aaaa": "a",
+ cpptr->IO.ConnectMe->Host,
+ cpptr->IO.ConnectMe->Port);
+
+ QueueQuery((cpptr->IO.ConnectMe->IPv6)? ns_t_aaaa : ns_t_a,
+ cpptr->IO.ConnectMe->Host,
+ &cpptr->IO,
+ &cpptr->HostLookup,
+ pop3_get_one_host_ip_done);
+ IO->NextState = eReadDNSReply;
+ return IO->NextState;
+}
+
+
+
+int pop3_do_fetching(pop3aggr *cpptr)
+{
+ AsyncIO *IO = &cpptr->IO;
+
+ InitIOStruct(IO,
+ cpptr,
+ eReadMessage,
+ POP3_C_ReadServerStatus,
+ POP3_C_DNSFail,
+ POP3_C_DispatchWriteDone,
+ POP3_C_DispatchReadDone,
+ POP3_C_Terminate,
+ POP3_C_TerminateDB,
+ POP3_C_ConnFail,
+ POP3_C_Timeout,
+ POP3_C_Shutdown);
+
+ safestrncpy(((CitContext *)cpptr->IO.CitContext)->cs_host,
+ ChrPtr(cpptr->Url),
+ sizeof(((CitContext *)cpptr->IO.CitContext)->cs_host));
+
+ if (cpptr->IO.ConnectMe->IsIP) {
+ QueueEventContext(&cpptr->IO,
+ pop3_connect_ip);
+ }
+ else {
+ QueueEventContext(&cpptr->IO,
+ pop3_get_one_host_ip);
+ }
+ return 1;
+}
+
+/*
+ * Scan a room's netconfig to determine whether it requires POP3 aggregation
+ */
+void pop3client_scan_room(struct ctdlroom *qrbuf, void *data, OneRoomNetCfg *OneRNCFG)
+{
+ const RoomNetCfgLine *pLine;
+ void *vptr;
+
+ pthread_mutex_lock(&POP3QueueMutex);
+ if (GetHash(POP3QueueRooms, LKEY(qrbuf->QRnumber), &vptr))
+ {
+ pthread_mutex_unlock(&POP3QueueMutex);
+ EVP3CQ_syslog(LOG_DEBUG,
+ "pop3client: [%ld] %s already in progress.",
+ qrbuf->QRnumber,
+ qrbuf->QRname);
+ return;
+ }
+ pthread_mutex_unlock(&POP3QueueMutex);
+
+ if (server_shutting_down) return;
+
+ pLine = OneRNCFG->NetConfigs[pop3client];
+
+ while (pLine != NULL)
+ {
+ pop3aggr *cptr;
+
+ cptr = (pop3aggr *) malloc(sizeof(pop3aggr));
+ memset(cptr, 0, sizeof(pop3aggr));
+ ///TODO do we need this? cptr->roomlist_parts=1;
+ cptr->RoomName = NewStrBufPlain(qrbuf->QRname, -1);
+ cptr->pop3user = NewStrBufDup(pLine->Value[1]);
+ cptr->pop3pass = NewStrBufDup(pLine->Value[2]);
+ cptr->Url = NewStrBuf();
+ cptr->Host = NewStrBufDup(pLine->Value[0]);
+
+ cptr->keep = atol(ChrPtr(pLine->Value[3]));
+ cptr->interval = atol(ChrPtr(pLine->Value[4]));
+
+ StrBufAppendBufPlain(cptr->Url, HKEY("pop3://"), 0);
+ StrBufUrlescUPAppend(cptr->Url, cptr->pop3user, NULL);
+ StrBufAppendBufPlain(cptr->Url, HKEY(":"), 0);
+ StrBufUrlescUPAppend(cptr->Url, cptr->pop3pass, NULL);
+ StrBufAppendBufPlain(cptr->Url, HKEY("@"), 0);
+ StrBufAppendBuf(cptr->Url, cptr->Host, 0);
+ StrBufAppendBufPlain(cptr->Url, HKEY("/"), 0);
+ StrBufUrlescAppend(cptr->Url, cptr->RoomName, NULL);
+
+ ParseURL(&cptr->IO.ConnectMe, cptr->Url, 110);
+
+
+#if 0
+/* todo: we need to reunite the url to be shure. */
+
+ pthread_mutex_lock(&POP3ueueMutex);
+ GetHash(POP3FetchUrls, SKEY(ptr->Url), &vptr);
+ use_this_cptr = (pop3aggr *)vptr;
+
+ if (use_this_rncptr != NULL)
+ {
+ /* mustn't attach to an active session */
+ if (use_this_cptr->RefCount > 0)
+ {
+ DeletePOP3Cfg(cptr);
+/// Count->count--;
+ }
+ else
+ {
+ long *QRnumber;
+ StrBufAppendBufPlain(
+ use_this_cptr->rooms,
+ qrbuf->QRname,
+ -1, 0);
+ if (use_this_cptr->roomlist_parts == 1)
+ {
+ use_this_cptr->OtherQRnumbers
+ = NewHash(1, lFlathash);
+ }
+ QRnumber = (long*)malloc(sizeof(long));
+ *QRnumber = qrbuf->QRnumber;
+ Put(use_this_cptr->OtherQRnumbers,
+ LKEY(qrbuf->QRnumber),
+ QRnumber,
+ NULL);
+
+ use_this_cptr->roomlist_parts++;
+ }
+ pthread_mutex_unlock(&POP3QueueMutex);
+ continue;
+ }
+ pthread_mutex_unlock(&RSSQueueMutex);
+#endif
+ cptr->n = Pop3ClientID++;
+ pthread_mutex_lock(&POP3QueueMutex);
+ Put(POP3FetchUrls,
+ SKEY(cptr->Url),
+ cptr,
+ DeletePOP3Aggregator);
+
+ pthread_mutex_unlock(&POP3QueueMutex);
+
+ }
+}
+
+static int doing_pop3client = 0;
+