| /* |
| * POP3 Transport |
| * |
| * Copyright 2008 Hans Leidekker for CodeWeavers |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #define COBJMACROS |
| #define NONAMELESSUNION |
| |
| #include <stdarg.h> |
| #include <stdio.h> |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "winnt.h" |
| #include "winuser.h" |
| #include "objbase.h" |
| #include "mimeole.h" |
| #include "wine/debug.h" |
| |
| #include "inetcomm_private.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(inetcomm); |
| |
| enum parse_state |
| { |
| STATE_NONE, |
| STATE_OK, |
| STATE_MULTILINE, |
| STATE_DONE |
| }; |
| |
| typedef struct |
| { |
| InternetTransport InetTransport; |
| ULONG refs; |
| POP3COMMAND command; |
| POP3CMDTYPE type; |
| char *response; |
| char *ptr; |
| enum parse_state state; |
| BOOL valid_info; |
| DWORD msgid; |
| DWORD preview_lines; |
| } POP3Transport; |
| |
| static HRESULT parse_response(POP3Transport *This) |
| { |
| switch (This->state) |
| { |
| case STATE_NONE: |
| { |
| if (strlen(This->response) < 3) |
| { |
| WARN("parse error\n"); |
| This->state = STATE_DONE; |
| return S_FALSE; |
| } |
| if (!memcmp(This->response, "+OK", 3)) |
| { |
| This->ptr = This->response + 3; |
| This->state = STATE_OK; |
| return S_OK; |
| } |
| This->state = STATE_DONE; |
| return S_FALSE; |
| } |
| default: return S_OK; |
| } |
| } |
| |
| static HRESULT parse_uidl_response(POP3Transport *This, POP3UIDL *uidl) |
| { |
| char *p; |
| |
| uidl->dwPopId = 0; |
| uidl->pszUidl = NULL; |
| switch (This->state) |
| { |
| case STATE_OK: |
| { |
| if (This->type == POP3CMD_GET_POPID) |
| { |
| if ((p = strchr(This->ptr, ' '))) |
| { |
| while (*p == ' ') p++; |
| sscanf(p, "%u", &uidl->dwPopId); |
| if ((p = strchr(p, ' '))) |
| { |
| while (*p == ' ') p++; |
| uidl->pszUidl = p; |
| This->valid_info = TRUE; |
| } |
| } |
| This->state = STATE_DONE; |
| return S_OK; |
| } |
| This->state = STATE_MULTILINE; |
| return S_OK; |
| } |
| case STATE_MULTILINE: |
| { |
| if (This->response[0] == '.' && !This->response[1]) |
| { |
| This->valid_info = FALSE; |
| This->state = STATE_DONE; |
| return S_OK; |
| } |
| sscanf(This->response, "%u", &uidl->dwPopId); |
| if ((p = strchr(This->response, ' '))) |
| { |
| while (*p == ' ') p++; |
| uidl->pszUidl = p; |
| This->valid_info = TRUE; |
| return S_OK; |
| } |
| } |
| default: |
| { |
| WARN("parse error\n"); |
| This->state = STATE_DONE; |
| return S_FALSE; |
| } |
| } |
| } |
| |
| static HRESULT parse_stat_response(POP3Transport *This, POP3STAT *stat) |
| { |
| char *p; |
| |
| stat->cMessages = 0; |
| stat->cbMessages = 0; |
| switch (This->state) |
| { |
| case STATE_OK: |
| { |
| if ((p = strchr(This->ptr, ' '))) |
| { |
| while (*p == ' ') p++; |
| sscanf(p, "%u %u", &stat->cMessages, &stat->cbMessages); |
| This->valid_info = TRUE; |
| This->state = STATE_DONE; |
| return S_OK; |
| } |
| } |
| default: |
| { |
| WARN("parse error\n"); |
| This->state = STATE_DONE; |
| return S_FALSE; |
| } |
| } |
| } |
| |
| static HRESULT parse_list_response(POP3Transport *This, POP3LIST *list) |
| { |
| char *p; |
| |
| list->dwPopId = 0; |
| list->cbSize = 0; |
| switch (This->state) |
| { |
| case STATE_OK: |
| { |
| if (This->type == POP3CMD_GET_POPID) |
| { |
| if ((p = strchr(This->ptr, ' '))) |
| { |
| while (*p == ' ') p++; |
| sscanf(p, "%u %u", &list->dwPopId, &list->cbSize); |
| This->valid_info = TRUE; |
| } |
| This->state = STATE_DONE; |
| return S_OK; |
| } |
| This->state = STATE_MULTILINE; |
| return S_OK; |
| } |
| case STATE_MULTILINE: |
| { |
| if (This->response[0] == '.' && !This->response[1]) |
| { |
| This->valid_info = FALSE; |
| This->state = STATE_DONE; |
| return S_OK; |
| } |
| sscanf(This->response, "%u", &list->dwPopId); |
| if ((p = strchr(This->response, ' '))) |
| { |
| while (*p == ' ') p++; |
| sscanf(p, "%u", &list->cbSize); |
| This->valid_info = TRUE; |
| return S_OK; |
| } |
| } |
| default: |
| { |
| WARN("parse error\n"); |
| This->state = STATE_DONE; |
| return S_FALSE; |
| } |
| } |
| } |
| |
| static HRESULT parse_dele_response(POP3Transport *This, DWORD *dwPopId) |
| { |
| switch (This->state) |
| { |
| case STATE_OK: |
| { |
| *dwPopId = 0; /* FIXME */ |
| This->state = STATE_DONE; |
| return S_OK; |
| } |
| default: |
| { |
| WARN("parse error\n"); |
| This->state = STATE_DONE; |
| return S_FALSE; |
| } |
| } |
| } |
| |
| static HRESULT parse_retr_response(POP3Transport *This, POP3RETR *retr) |
| { |
| switch (This->state) |
| { |
| case STATE_OK: |
| { |
| retr->fHeader = FALSE; |
| retr->fBody = FALSE; |
| retr->dwPopId = This->msgid; |
| retr->cbSoFar = 0; |
| retr->pszLines = This->response; |
| retr->cbLines = 0; |
| |
| This->state = STATE_MULTILINE; |
| This->valid_info = FALSE; |
| return S_OK; |
| } |
| case STATE_MULTILINE: |
| { |
| int len; |
| |
| if (This->response[0] == '.' && !This->response[1]) |
| { |
| retr->cbLines = retr->cbSoFar; |
| This->state = STATE_DONE; |
| return S_OK; |
| } |
| retr->fHeader = TRUE; |
| if (!This->response[0]) retr->fBody = TRUE; |
| |
| len = strlen(This->response); |
| retr->cbSoFar += len; |
| retr->pszLines = This->response; |
| retr->cbLines = len; |
| |
| This->valid_info = TRUE; |
| return S_OK; |
| } |
| default: |
| { |
| WARN("parse error\n"); |
| This->state = STATE_DONE; |
| return S_FALSE; |
| } |
| } |
| } |
| |
| static HRESULT parse_top_response(POP3Transport *This, POP3TOP *top) |
| { |
| switch (This->state) |
| { |
| case STATE_OK: |
| { |
| top->fHeader = FALSE; |
| top->fBody = FALSE; |
| top->dwPopId = This->msgid; |
| top->cPreviewLines = This->preview_lines; |
| top->cbSoFar = 0; |
| top->pszLines = This->response; |
| top->cbLines = 0; |
| |
| This->state = STATE_MULTILINE; |
| This->valid_info = FALSE; |
| return S_OK; |
| } |
| case STATE_MULTILINE: |
| { |
| int len; |
| |
| if (This->response[0] == '.' && !This->response[1]) |
| { |
| top->cbLines = top->cbSoFar; |
| This->state = STATE_DONE; |
| return S_OK; |
| } |
| top->fHeader = TRUE; |
| if (!This->response[0]) top->fBody = TRUE; |
| |
| len = strlen(This->response); |
| top->cbSoFar += len; |
| top->pszLines = This->response; |
| top->cbLines = len; |
| |
| This->valid_info = TRUE; |
| return S_OK; |
| } |
| default: |
| { |
| WARN("parse error\n"); |
| This->state = STATE_DONE; |
| return S_FALSE; |
| } |
| } |
| } |
| |
| static void init_parser(POP3Transport *This, POP3COMMAND command, POP3CMDTYPE type) |
| { |
| This->state = STATE_NONE; |
| This->command = command; |
| This->type = type; |
| } |
| |
| static HRESULT POP3Transport_ParseResponse(POP3Transport *This, char *pszResponse, POP3RESPONSE *pResponse) |
| { |
| HRESULT hr; |
| |
| TRACE("response: %s\n", debugstr_a(pszResponse)); |
| |
| This->response = pszResponse; |
| This->valid_info = FALSE; |
| TRACE("state %u\n", This->state); |
| |
| if (SUCCEEDED((hr = parse_response(This)))) |
| { |
| switch (This->command) |
| { |
| case POP3_UIDL: hr = parse_uidl_response(This, &pResponse->u.rUidlInfo); break; |
| case POP3_STAT: hr = parse_stat_response(This, &pResponse->u.rStatInfo); break; |
| case POP3_LIST: hr = parse_list_response(This, &pResponse->u.rListInfo); break; |
| case POP3_DELE: hr = parse_dele_response(This, &pResponse->u.dwPopId); break; |
| case POP3_RETR: hr = parse_retr_response(This, &pResponse->u.rRetrInfo); break; |
| case POP3_TOP: hr = parse_top_response(This, &pResponse->u.rTopInfo); break; |
| default: |
| This->state = STATE_DONE; |
| break; |
| } |
| } |
| pResponse->command = This->command; |
| pResponse->fDone = (This->state == STATE_DONE); |
| pResponse->fValidInfo = This->valid_info; |
| pResponse->rIxpResult.hrResult = hr; |
| pResponse->rIxpResult.pszResponse = pszResponse; |
| pResponse->rIxpResult.uiServerError = 0; |
| pResponse->rIxpResult.hrServerError = pResponse->rIxpResult.hrResult; |
| pResponse->rIxpResult.dwSocketError = WSAGetLastError(); |
| pResponse->rIxpResult.pszProblem = NULL; |
| pResponse->pTransport = (IPOP3Transport *)&This->InetTransport.u.vtblPOP3; |
| |
| if (This->InetTransport.pCallback && This->InetTransport.fCommandLogging) |
| { |
| ITransportCallback_OnCommand(This->InetTransport.pCallback, CMD_RESP, |
| pResponse->rIxpResult.pszResponse, pResponse->rIxpResult.hrServerError, |
| (IInternetTransport *)&This->InetTransport.u.vtbl); |
| } |
| return S_OK; |
| } |
| |
| static void POP3Transport_CallbackProcessDELEResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| POP3RESPONSE response; |
| HRESULT hr; |
| |
| TRACE("\n"); |
| |
| hr = POP3Transport_ParseResponse(This, pBuffer, &response); |
| if (FAILED(hr)) |
| { |
| /* FIXME: handle error */ |
| return; |
| } |
| |
| IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); |
| } |
| |
| static void POP3Transport_CallbackRecvDELEResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| |
| TRACE("\n"); |
| InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessDELEResp); |
| } |
| |
| static void POP3Transport_CallbackProcessNOOPResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| POP3RESPONSE response; |
| HRESULT hr; |
| |
| TRACE("\n"); |
| |
| hr = POP3Transport_ParseResponse(This, pBuffer, &response); |
| if (FAILED(hr)) |
| { |
| /* FIXME: handle error */ |
| return; |
| } |
| |
| IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); |
| } |
| |
| static void POP3Transport_CallbackRecvNOOPResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| |
| TRACE("\n"); |
| InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessNOOPResp); |
| } |
| |
| static void POP3Transport_CallbackProcessRSETResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| POP3RESPONSE response; |
| HRESULT hr; |
| |
| TRACE("\n"); |
| |
| hr = POP3Transport_ParseResponse(This, pBuffer, &response); |
| if (FAILED(hr)) |
| { |
| /* FIXME: handle error */ |
| return; |
| } |
| |
| IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); |
| } |
| |
| static void POP3Transport_CallbackRecvRSETResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| |
| TRACE("\n"); |
| InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessRSETResp); |
| } |
| |
| static void POP3Transport_CallbackProcessRETRResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| POP3RESPONSE response; |
| HRESULT hr; |
| |
| TRACE("\n"); |
| |
| hr = POP3Transport_ParseResponse(This, pBuffer, &response); |
| if (FAILED(hr)) |
| { |
| /* FIXME: handle error */ |
| return; |
| } |
| |
| IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); |
| |
| if (!response.fDone) |
| { |
| InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessRETRResp); |
| return; |
| } |
| |
| IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); |
| } |
| |
| static void POP3Transport_CallbackRecvRETRResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| |
| TRACE("\n"); |
| InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessRETRResp); |
| } |
| |
| static void POP3Transport_CallbackProcessTOPResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| POP3RESPONSE response; |
| HRESULT hr; |
| |
| TRACE("\n"); |
| |
| hr = POP3Transport_ParseResponse(This, pBuffer, &response); |
| if (FAILED(hr)) |
| { |
| /* FIXME: handle error */ |
| return; |
| } |
| |
| IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); |
| |
| if (!response.fDone) |
| { |
| InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessTOPResp); |
| return; |
| } |
| |
| IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); |
| } |
| |
| static void POP3Transport_CallbackRecvTOPResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| |
| TRACE("\n"); |
| InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessTOPResp); |
| } |
| |
| static void POP3Transport_CallbackProcessLISTResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| POP3RESPONSE response; |
| HRESULT hr; |
| |
| TRACE("\n"); |
| |
| hr = POP3Transport_ParseResponse(This, pBuffer, &response); |
| if (FAILED(hr)) |
| { |
| /* FIXME: handle error */ |
| return; |
| } |
| |
| IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); |
| |
| if (!response.fDone) |
| { |
| InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessLISTResp); |
| return; |
| } |
| |
| IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); |
| } |
| |
| static void POP3Transport_CallbackRecvLISTResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| |
| TRACE("\n"); |
| InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessLISTResp); |
| } |
| |
| static void POP3Transport_CallbackProcessUIDLResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| POP3RESPONSE response; |
| HRESULT hr; |
| |
| TRACE("\n"); |
| |
| hr = POP3Transport_ParseResponse(This, pBuffer, &response); |
| if (FAILED(hr)) |
| { |
| /* FIXME: handle error */ |
| return; |
| } |
| |
| IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); |
| |
| if (!response.fDone) |
| { |
| InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessUIDLResp); |
| return; |
| } |
| |
| IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); |
| } |
| |
| static void POP3Transport_CallbackRecvUIDLResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| |
| TRACE("\n"); |
| InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessUIDLResp); |
| } |
| |
| static void POP3Transport_CallbackProcessSTATResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| POP3RESPONSE response; |
| HRESULT hr; |
| |
| TRACE("\n"); |
| |
| hr = POP3Transport_ParseResponse(This, pBuffer, &response); |
| if (FAILED(hr)) |
| { |
| /* FIXME: handle error */ |
| return; |
| } |
| |
| IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); |
| } |
| |
| static void POP3Transport_CallbackRecvSTATResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| |
| TRACE("\n"); |
| InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessSTATResp); |
| } |
| |
| static void POP3Transport_CallbackProcessPASSResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| POP3RESPONSE response; |
| HRESULT hr; |
| |
| TRACE("\n"); |
| |
| hr = POP3Transport_ParseResponse(This, pBuffer, &response); |
| if (FAILED(hr)) |
| { |
| /* FIXME: handle error */ |
| return; |
| } |
| |
| InternetTransport_ChangeStatus(&This->InetTransport, IXP_AUTHORIZED); |
| InternetTransport_ChangeStatus(&This->InetTransport, IXP_CONNECTED); |
| |
| IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); |
| } |
| |
| static void POP3Transport_CallbackRecvPASSResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| |
| TRACE("\n"); |
| InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessPASSResp); |
| } |
| |
| static void POP3Transport_CallbackProcessUSERResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) |
| { |
| static char pass[] = "PASS "; |
| POP3Transport *This = (POP3Transport *)iface; |
| POP3RESPONSE response; |
| char *command; |
| int len; |
| HRESULT hr; |
| |
| TRACE("\n"); |
| |
| hr = POP3Transport_ParseResponse(This, pBuffer, &response); |
| if (FAILED(hr)) |
| { |
| /* FIXME: handle error */ |
| return; |
| } |
| |
| IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); |
| |
| len = sizeof(pass) + strlen(This->InetTransport.ServerInfo.szPassword) + 2; /* "\r\n" */ |
| command = HeapAlloc(GetProcessHeap(), 0, len); |
| |
| strcpy(command, pass); |
| strcat(command, This->InetTransport.ServerInfo.szPassword); |
| strcat(command, "\r\n"); |
| |
| init_parser(This, POP3_PASS, POP3_NONE); |
| |
| InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvPASSResp); |
| HeapFree(GetProcessHeap(), 0, command); |
| } |
| |
| static void POP3Transport_CallbackRecvUSERResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| |
| TRACE("\n"); |
| InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessUSERResp); |
| } |
| |
| static void POP3Transport_CallbackSendUSERCmd(IInternetTransport *iface, char *pBuffer, int cbBuffer) |
| { |
| static char user[] = "USER "; |
| POP3Transport *This = (POP3Transport *)iface; |
| char *command; |
| int len; |
| |
| TRACE("\n"); |
| |
| len = sizeof(user) + strlen(This->InetTransport.ServerInfo.szUserName) + 2; /* "\r\n" */ |
| command = HeapAlloc(GetProcessHeap(), 0, len); |
| |
| strcpy(command, user); |
| strcat(command, This->InetTransport.ServerInfo.szUserName); |
| strcat(command, "\r\n"); |
| InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvUSERResp); |
| |
| HeapFree(GetProcessHeap(), 0, command); |
| } |
| |
| static void POP3Transport_CallbackProcessQUITResponse(IInternetTransport *iface, char *pBuffer, int cbBuffer) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| POP3RESPONSE response; |
| HRESULT hr; |
| |
| TRACE("%s\n", debugstr_an(pBuffer, cbBuffer)); |
| |
| hr = POP3Transport_ParseResponse(This, pBuffer, &response); |
| if (FAILED(hr)) |
| { |
| /* FIXME: handle error */ |
| return; |
| } |
| |
| IPOP3Callback_OnResponse((IPOP3Callback *)This->InetTransport.pCallback, &response); |
| InternetTransport_DropConnection(&This->InetTransport); |
| } |
| |
| static void POP3Transport_CallbackRecvQUITResp(IInternetTransport *iface, char *pBuffer, int cbBuffer) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| |
| TRACE("\n"); |
| InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackProcessQUITResponse); |
| } |
| |
| static HRESULT WINAPI POP3Transport_QueryInterface(IPOP3Transport *iface, REFIID riid, void **ppv) |
| { |
| TRACE("(%s, %p)\n", debugstr_guid(riid), ppv); |
| |
| if (IsEqualIID(riid, &IID_IUnknown) || |
| IsEqualIID(riid, &IID_IInternetTransport) || |
| IsEqualIID(riid, &IID_IPOP3Transport)) |
| { |
| *ppv = iface; |
| IUnknown_AddRef(iface); |
| return S_OK; |
| } |
| *ppv = NULL; |
| FIXME("no interface for %s\n", debugstr_guid(riid)); |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG WINAPI POP3Transport_AddRef(IPOP3Transport *iface) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| return InterlockedIncrement((LONG *)&This->refs); |
| } |
| |
| static ULONG WINAPI POP3Transport_Release(IPOP3Transport *iface) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| ULONG refs = InterlockedDecrement((LONG *)&This->refs); |
| if (!refs) |
| { |
| TRACE("destroying %p\n", This); |
| if (This->InetTransport.Status != IXP_DISCONNECTED) |
| InternetTransport_DropConnection(&This->InetTransport); |
| if (This->InetTransport.pCallback) ITransportCallback_Release(This->InetTransport.pCallback); |
| HeapFree(GetProcessHeap(), 0, This); |
| } |
| return refs; |
| } |
| |
| static HRESULT WINAPI POP3Transport_GetServerInfo(IPOP3Transport *iface, |
| LPINETSERVER pInetServer) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| |
| TRACE("(%p)\n", pInetServer); |
| return InternetTransport_GetServerInfo(&This->InetTransport, pInetServer); |
| } |
| |
| static IXPTYPE WINAPI POP3Transport_GetIXPType(IPOP3Transport *iface) |
| { |
| TRACE("()\n"); |
| return IXP_POP3; |
| } |
| |
| static HRESULT WINAPI POP3Transport_IsState(IPOP3Transport *iface, IXPISSTATE isstate) |
| { |
| FIXME("(%u)\n", isstate); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI POP3Transport_InetServerFromAccount( |
| IPOP3Transport *iface, IImnAccount *pAccount, LPINETSERVER pInetServer) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| |
| TRACE("(%p, %p)\n", pAccount, pInetServer); |
| return InternetTransport_InetServerFromAccount(&This->InetTransport, pAccount, pInetServer); |
| } |
| |
| static HRESULT WINAPI POP3Transport_Connect(IPOP3Transport *iface, |
| LPINETSERVER pInetServer, boolean fAuthenticate, boolean fCommandLogging) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| HRESULT hr; |
| |
| TRACE("(%p, %s, %s)\n", pInetServer, fAuthenticate ? "TRUE" : "FALSE", fCommandLogging ? "TRUE" : "FALSE"); |
| |
| hr = InternetTransport_Connect(&This->InetTransport, pInetServer, fAuthenticate, fCommandLogging); |
| if (FAILED(hr)) |
| return hr; |
| |
| init_parser(This, POP3_USER, POP3_NONE); |
| return InternetTransport_ReadLine(&This->InetTransport, POP3Transport_CallbackSendUSERCmd); |
| } |
| |
| static HRESULT WINAPI POP3Transport_HandsOffCallback(IPOP3Transport *iface) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| |
| TRACE("()\n"); |
| return InternetTransport_HandsOffCallback(&This->InetTransport); |
| } |
| |
| static HRESULT WINAPI POP3Transport_Disconnect(IPOP3Transport *iface) |
| { |
| TRACE("()\n"); |
| return IPOP3Transport_CommandQUIT(iface); |
| } |
| |
| static HRESULT WINAPI POP3Transport_DropConnection(IPOP3Transport *iface) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| |
| TRACE("()\n"); |
| return InternetTransport_DropConnection(&This->InetTransport); |
| } |
| |
| static HRESULT WINAPI POP3Transport_GetStatus(IPOP3Transport *iface, |
| IXPSTATUS *pCurrentStatus) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| |
| TRACE("()\n"); |
| return InternetTransport_GetStatus(&This->InetTransport, pCurrentStatus); |
| } |
| |
| static HRESULT WINAPI POP3Transport_InitNew(IPOP3Transport *iface, |
| LPSTR pszLogFilePath, IPOP3Callback *pCallback) |
| { |
| POP3Transport *This = (POP3Transport *)iface; |
| |
| TRACE("(%s, %p)\n", debugstr_a(pszLogFilePath), pCallback); |
| |
| if (!pCallback) |
| return E_INVALIDARG; |
| |
| if (pszLogFilePath) |
| FIXME("not using log file of %s, use Wine debug logging instead\n", |
| debugstr_a(pszLogFilePath)); |
| |
| IPOP3Callback_AddRef(pCallback); |
| This->InetTransport.pCallback = (ITransportCallback *)pCallback; |
| This->InetTransport.fInitialised = TRUE; |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI POP3Transport_MarkItem(IPOP3Transport *iface, POP3MARKTYPE marktype, |
| DWORD dwPopId, boolean fMarked) |
| { |
| FIXME("(%u, %u, %d)\n", marktype, dwPopId, fMarked); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI POP3Transport_CommandAUTH(IPOP3Transport *iface, LPSTR pszAuthType) |
| { |
| FIXME("(%s)\n", pszAuthType); |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI POP3Transport_CommandUSER(IPOP3Transport *iface, LPSTR username) |
| { |
| static char user[] = "USER "; |
| POP3Transport *This = (POP3Transport *)iface; |
| char *command; |
| int len; |
| |
| TRACE("(%s)\n", username); |
| |
| len = sizeof(user) + strlen(username) + 2; /* "\r\n" */ |
| if (!(command = HeapAlloc(GetProcessHeap(), 0, len))) return S_FALSE; |
| |
| strcpy(command, user); |
| strcat(command, username); |
| strcat(command, "\r\n"); |
| |
| init_parser(This, POP3_USER, POP3_NONE); |
| InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvUSERResp); |
| |
| HeapFree(GetProcessHeap(), 0, command); |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI POP3Transport_CommandPASS(IPOP3Transport *iface, LPSTR password) |
| { |
| static char pass[] = "PASS "; |
| POP3Transport *This = (POP3Transport *)iface; |
| char *command; |
| int len; |
| |
| TRACE("(%p)\n", password); |
| |
| len = sizeof(pass) + strlen(password) + 2; /* "\r\n" */ |
| if (!(command = HeapAlloc(GetProcessHeap(), 0, len))) return S_FALSE; |
| |
| strcpy(command, pass); |
| strcat(command, password); |
| strcat(command, "\r\n"); |
| |
| init_parser(This, POP3_PASS, POP3_NONE); |
| InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvPASSResp); |
| |
| HeapFree(GetProcessHeap(), 0, command); |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI POP3Transport_CommandLIST( |
| IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId) |
| { |
| static char list[] = "LIST %u\r\n"; |
| static char list_all[] = "LIST\r\n"; |
| POP3Transport *This = (POP3Transport *)iface; |
| char *command; |
| int len; |
| |
| TRACE("(%u, %u)\n", cmdtype, dwPopId); |
| |
| if (dwPopId) |
| { |
| len = sizeof(list) + 10 + 2; /* "4294967296" + "\r\n" */ |
| if (!(command = HeapAlloc(GetProcessHeap(), 0, len))) return S_FALSE; |
| sprintf(command, list, dwPopId); |
| } |
| else command = list_all; |
| |
| init_parser(This, POP3_LIST, cmdtype); |
| InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvLISTResp); |
| |
| if (dwPopId) HeapFree(GetProcessHeap(), 0, command); |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI POP3Transport_CommandTOP( |
| IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId, DWORD cPreviewLines) |
| { |
| static char top[] = "TOP %u %u\r\n"; |
| POP3Transport *This = (POP3Transport *)iface; |
| char *command; |
| int len; |
| |
| TRACE("(%u, %u, %u)\n", cmdtype, dwPopId, cPreviewLines); |
| |
| len = sizeof(top) + 20 + 2; /* 2 * "4294967296" + "\r\n" */ |
| if (!(command = HeapAlloc(GetProcessHeap(), 0, len))) return S_FALSE; |
| sprintf(command, top, dwPopId, cPreviewLines); |
| |
| This->preview_lines = cPreviewLines; |
| init_parser(This, POP3_TOP, cmdtype); |
| InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvTOPResp); |
| |
| HeapFree(GetProcessHeap(), 0, command); |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI POP3Transport_CommandQUIT(IPOP3Transport *iface) |
| { |
| static char command[] = "QUIT\r\n"; |
| POP3Transport *This = (POP3Transport *)iface; |
| |
| TRACE("()\n"); |
| |
| InternetTransport_ChangeStatus(&This->InetTransport, IXP_DISCONNECTING); |
| |
| init_parser(This, POP3_QUIT, POP3_NONE); |
| return InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvQUITResp); |
| } |
| |
| static HRESULT WINAPI POP3Transport_CommandSTAT(IPOP3Transport *iface) |
| { |
| static char stat[] = "STAT\r\n"; |
| POP3Transport *This = (POP3Transport *)iface; |
| |
| TRACE("\n"); |
| |
| init_parser(This, POP3_STAT, POP3_NONE); |
| InternetTransport_DoCommand(&This->InetTransport, stat, POP3Transport_CallbackRecvSTATResp); |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI POP3Transport_CommandNOOP(IPOP3Transport *iface) |
| { |
| static char noop[] = "NOOP\r\n"; |
| POP3Transport *This = (POP3Transport *)iface; |
| |
| TRACE("\n"); |
| |
| init_parser(This, POP3_NOOP, POP3_NONE); |
| InternetTransport_DoCommand(&This->InetTransport, noop, POP3Transport_CallbackRecvNOOPResp); |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI POP3Transport_CommandRSET(IPOP3Transport *iface) |
| { |
| static char rset[] = "RSET\r\n"; |
| POP3Transport *This = (POP3Transport *)iface; |
| |
| TRACE("\n"); |
| |
| init_parser(This, POP3_RSET, POP3_NONE); |
| InternetTransport_DoCommand(&This->InetTransport, rset, POP3Transport_CallbackRecvRSETResp); |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI POP3Transport_CommandUIDL( |
| IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId) |
| { |
| static char uidl[] = "UIDL %u\r\n"; |
| static char uidl_all[] = "UIDL\r\n"; |
| POP3Transport *This = (POP3Transport *)iface; |
| char *command; |
| int len; |
| |
| TRACE("(%u, %u)\n", cmdtype, dwPopId); |
| |
| if (dwPopId) |
| { |
| len = sizeof(uidl) + 10 + 2; /* "4294967296" + "\r\n" */ |
| if (!(command = HeapAlloc(GetProcessHeap(), 0, len))) return S_FALSE; |
| sprintf(command, uidl, dwPopId); |
| } |
| else command = uidl_all; |
| |
| init_parser(This, POP3_UIDL, cmdtype); |
| InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvUIDLResp); |
| |
| if (dwPopId) HeapFree(GetProcessHeap(), 0, command); |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI POP3Transport_CommandDELE( |
| IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId) |
| { |
| static char dele[] = "DELE %u\r\n"; |
| POP3Transport *This = (POP3Transport *)iface; |
| char *command; |
| int len; |
| |
| TRACE("(%u, %u)\n", cmdtype, dwPopId); |
| |
| len = sizeof(dele) + 10 + 2; /* "4294967296" + "\r\n" */ |
| if (!(command = HeapAlloc(GetProcessHeap(), 0, len))) return S_FALSE; |
| sprintf(command, dele, dwPopId); |
| |
| init_parser(This, POP3_DELE, cmdtype); |
| InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvDELEResp); |
| |
| HeapFree(GetProcessHeap(), 0, command); |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI POP3Transport_CommandRETR( |
| IPOP3Transport *iface, POP3CMDTYPE cmdtype, DWORD dwPopId) |
| { |
| static char retr[] = "RETR %u\r\n"; |
| POP3Transport *This = (POP3Transport *)iface; |
| char *command; |
| int len; |
| |
| TRACE("(%u, %u)\n", cmdtype, dwPopId); |
| |
| len = sizeof(retr) + 10 + 2; /* "4294967296" + "\r\n" */ |
| if (!(command = HeapAlloc(GetProcessHeap(), 0, len))) return S_FALSE; |
| sprintf(command, retr, dwPopId); |
| |
| init_parser(This, POP3_RETR, cmdtype); |
| InternetTransport_DoCommand(&This->InetTransport, command, POP3Transport_CallbackRecvRETRResp); |
| |
| HeapFree(GetProcessHeap(), 0, command); |
| return S_OK; |
| } |
| |
| static const IPOP3TransportVtbl POP3TransportVtbl = |
| { |
| POP3Transport_QueryInterface, |
| POP3Transport_AddRef, |
| POP3Transport_Release, |
| POP3Transport_GetServerInfo, |
| POP3Transport_GetIXPType, |
| POP3Transport_IsState, |
| POP3Transport_InetServerFromAccount, |
| POP3Transport_Connect, |
| POP3Transport_HandsOffCallback, |
| POP3Transport_Disconnect, |
| POP3Transport_DropConnection, |
| POP3Transport_GetStatus, |
| POP3Transport_InitNew, |
| POP3Transport_MarkItem, |
| POP3Transport_CommandAUTH, |
| POP3Transport_CommandUSER, |
| POP3Transport_CommandPASS, |
| POP3Transport_CommandLIST, |
| POP3Transport_CommandTOP, |
| POP3Transport_CommandQUIT, |
| POP3Transport_CommandSTAT, |
| POP3Transport_CommandNOOP, |
| POP3Transport_CommandRSET, |
| POP3Transport_CommandUIDL, |
| POP3Transport_CommandDELE, |
| POP3Transport_CommandRETR |
| }; |
| |
| HRESULT WINAPI CreatePOP3Transport(IPOP3Transport **ppTransport) |
| { |
| HRESULT hr; |
| POP3Transport *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); |
| if (!This) |
| return E_OUTOFMEMORY; |
| |
| This->InetTransport.u.vtblPOP3 = &POP3TransportVtbl; |
| This->refs = 0; |
| hr = InternetTransport_Init(&This->InetTransport); |
| if (FAILED(hr)) |
| { |
| HeapFree(GetProcessHeap(), 0, This); |
| return hr; |
| } |
| |
| *ppTransport = (IPOP3Transport *)&This->InetTransport.u.vtblPOP3; |
| IPOP3Transport_AddRef(*ppTransport); |
| |
| return S_OK; |
| } |
| |
| static HRESULT WINAPI POP3TransportCF_QueryInterface(LPCLASSFACTORY iface, |
| REFIID riid, LPVOID *ppv) |
| { |
| *ppv = NULL; |
| if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory)) |
| { |
| *ppv = iface; |
| IUnknown_AddRef(iface); |
| return S_OK; |
| } |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG WINAPI POP3TransportCF_AddRef(LPCLASSFACTORY iface) |
| { |
| return 2; /* non-heap based object */ |
| } |
| |
| static ULONG WINAPI POP3TransportCF_Release(LPCLASSFACTORY iface) |
| { |
| return 1; /* non-heap based object */ |
| } |
| |
| static HRESULT WINAPI POP3TransportCF_CreateInstance(LPCLASSFACTORY iface, |
| LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv) |
| { |
| HRESULT hr; |
| IPOP3Transport *pPop3Transport; |
| |
| TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv); |
| |
| *ppv = NULL; |
| |
| if (pUnk) |
| return CLASS_E_NOAGGREGATION; |
| |
| hr = CreatePOP3Transport(&pPop3Transport); |
| if (FAILED(hr)) |
| return hr; |
| |
| hr = IPOP3Transport_QueryInterface(pPop3Transport, riid, ppv); |
| IPOP3Transport_Release(pPop3Transport); |
| |
| return hr; |
| } |
| |
| static HRESULT WINAPI POP3TransportCF_LockServer(LPCLASSFACTORY iface, BOOL fLock) |
| { |
| FIXME("(%d)\n",fLock); |
| return S_OK; |
| } |
| |
| static const IClassFactoryVtbl POP3TransportCFVtbl = |
| { |
| POP3TransportCF_QueryInterface, |
| POP3TransportCF_AddRef, |
| POP3TransportCF_Release, |
| POP3TransportCF_CreateInstance, |
| POP3TransportCF_LockServer |
| }; |
| static const IClassFactoryVtbl *POP3TransportCF = &POP3TransportCFVtbl; |
| |
| HRESULT POP3TransportCF_Create(REFIID riid, LPVOID *ppv) |
| { |
| return IClassFactory_QueryInterface((IClassFactory *)&POP3TransportCF, riid, ppv); |
| } |