/*
 * Copyright 2006 Robert Shearman 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
 */

import "imnact.idl";

interface IInternetTransport;
interface ISMTPTransport;
interface IPOP3Transport;
interface IIMAPTransport;

/* CLSIDs */

cpp_quote("DEFINE_GUID(CLSID_IInternetMessageUrl, 0xca30cc91, 0xb1b3, 0x11d0, 0x85, 0xd0, 0x00, 0xc0, 0x4f, 0xd8, 0x5a, 0xb4);")
cpp_quote("DEFINE_GUID(CLSID_ISMTPTransport, 0xfd853ce6, 0x7f86, 0x11d0, 0x82, 0x52, 0x00, 0xc0, 0x4f, 0xd8, 0x5a, 0xb4);")
cpp_quote("DEFINE_GUID(CLSID_ISMTPTransport2, 0xdf2c7eC, 0x3435, 0x11d0, 0x81, 0xd0, 0x0, 0xc0, 0x4f, 0xd8, 0x5a, 0xb4);")
cpp_quote("DEFINE_GUID(CLSID_IPOP3Transport, 0xfd853ce7, 0x7f86, 0x11d0, 0x82, 0x52, 0x00, 0xc0, 0x4f, 0xd8, 0x5a, 0xb4);")
cpp_quote("DEFINE_GUID(CLSID_INNTPTransport, 0xfd853ce8, 0x7f86, 0x11d0, 0x82, 0x52, 0x00, 0xc0, 0x4f, 0xd8, 0x5a, 0xb4);")
cpp_quote("DEFINE_GUID(CLSID_IRASTransport, 0xfd853ce9, 0x7f86, 0x11d0, 0x82, 0x52, 0x00, 0xc0, 0x4f, 0xd8, 0x5a, 0xb4);")
cpp_quote("DEFINE_GUID(CLSID_IRangeList, 0xfd853cea, 0x7f86, 0x11d0, 0x82, 0x52, 0x00, 0xc0, 0x4f, 0xd8, 0x5a, 0xb4);")
cpp_quote("DEFINE_GUID(CLSID_IIMAPTransport, 0xfd853ceb, 0x7f86, 0x11d0, 0x82, 0x52, 0x00, 0xc0, 0x4f, 0xd8, 0x5a, 0xb4);")
cpp_quote("DEFINE_GUID(CLSID_IHTTPMailTransport, 0x5a580c11, 0xe5eb, 0x11d1, 0xa8, 0x6e, 0x00, 0x00, 0xf8, 0x08, 0x4f, 0x96);")
cpp_quote("DEFINE_GUID(CLSID_IPropFindRequest, 0xbb847b8a, 0x054a, 0x11d2, 0xa8, 0x94, 0x00, 0x00, 0xf8, 0x08, 0x4f, 0x96);")
cpp_quote("DEFINE_GUID(CLSID_IPropPatchRequest, 0xea678830, 0x235d, 0x11d2, 0xa8, 0xb6, 0x00, 0x00, 0xf8, 0x08, 0x4f, 0x96);")

/* Error Codes */

cpp_quote("#ifndef HR_E")
cpp_quote("#define HR_E(n) MAKE_SCODE(SEVERITY_ERROR, FACILITY_INTERNET, n)")
cpp_quote("#endif")
cpp_quote("#ifndef HR_S")
cpp_quote("#define HR_S(n) MAKE_SCODE(SEVERITY_SUCCESS, FACILITY_INTERNET, n)")
cpp_quote("#endif")

/* General Error Codes */
cpp_quote("#define IXP_E_LOAD_SICILY_FAILED     HR_E(0xCC00)")
cpp_quote("#define IXP_E_INVALID_CERT_CN        HR_E(0xCC01)")
cpp_quote("#define IXP_E_INVALID_CERT_DATE      HR_E(0xCC02)")
cpp_quote("#define IXP_E_ALREADY_CONNECTED      HR_E(0xCC03)")
cpp_quote("#define IXP_E_CONN                   HR_E(0xCC04)")
cpp_quote("#define IXP_E_NOT_CONNECTED          HR_E(0xCC05)")
cpp_quote("#define IXP_E_CONN_SEND              HR_E(0xCC06)")
cpp_quote("#define IXP_E_WOULD_BLOCK            HR_E(0xCC07)")
cpp_quote("#define IXP_E_INVALID_STATE          HR_E(0xCC08)")
cpp_quote("#define IXP_E_CONN_RECV              HR_E(0xCC09)")
cpp_quote("#define IXP_E_INCOMPLETE             HR_E(0xCC0A)")
cpp_quote("#define IXP_E_BUSY                   HR_E(0xCC0B)")
cpp_quote("#define IXP_E_NOT_INIT               HR_E(0xCC0C)")
cpp_quote("#define IXP_E_CANT_FIND_HOST         HR_E(0xCC0D)")
cpp_quote("#define IXP_E_FAILED_TO_CONNECT      HR_E(0xCC0E)")
cpp_quote("#define IXP_E_CONNECTION_DROPPED     HR_E(0xCC0F)")
cpp_quote("#define IXP_E_INVALID_ADDRESS        HR_E(0xCC10)")
cpp_quote("#define IXP_E_INVALID_ADDRESS_LIST   HR_E(0xCC11)")
cpp_quote("#define IXP_E_SOCKET_READ_ERROR      HR_E(0xCC12)")
cpp_quote("#define IXP_E_SOCKET_WRITE_ERROR     HR_E(0xCC13)")
cpp_quote("#define IXP_E_SCOKET_INIT_ERROR      HR_E(0xCC14)")
cpp_quote("#define IXP_E_SOCKET_CONNECT_ERROR   HR_E(0xCC15)")
cpp_quote("#define IXP_E_INVALID_ACCOUNT        HR_E(0xCC16)")
cpp_quote("#define IXP_E_USER_CANCEL            HR_E(0xCC17)")
cpp_quote("#define IXP_E_SICILY_LOGON_FAILED    HR_E(0xCC18)")
cpp_quote("#define IXP_E_TIMEOUT                HR_E(0xCC19)")
cpp_quote("#define IXP_E_SECURE_CONNECT_FAILED  HR_E(0xCC1A)")

/* SMTP Failure Statuses */
cpp_quote("#define IXP_E_SMTP_RESPONSE_ERROR            HR_E(0xCC60)")
cpp_quote("#define IXP_E_SMTP_UNKNOWN_RESPONSE_CODE     HR_E(0xCC61)")
cpp_quote("#define IXP_E_SMTP_500_SYNTAX_ERROR          HR_E(0xCC62)")
cpp_quote("#define IXP_E_SMTP_501_PARAM_SYNTAX          HR_E(0xCC63)")
cpp_quote("#define IXP_E_SMTP_502_COMMAND_NOTIMPL       HR_E(0xCC64)")
cpp_quote("#define IXP_E_SMTP_503_COMMAND_SEQ           HR_E(0xCC65)")
cpp_quote("#define IXP_E_SMTP_504_COMMAND_PARAM_NOTIMPL HR_E(0xCC66)")
cpp_quote("#define IXP_E_SMTP_421_NOT_AVAILABLE         HR_E(0xCC67)")
cpp_quote("#define IXP_E_SMTP_450_MAILBOX_BUSY          HR_E(0xCC68)")
cpp_quote("#define IXP_E_SMTP_550_MAILBOX_NOT_FOUND     HR_E(0xCC69)")
cpp_quote("#define IXP_E_SMTP_451_ERROR_PROCESSING      HR_E(0xCC6A)")
cpp_quote("#define IXP_E_SMTP_551_USER_NOT_LOCAL        HR_E(0xCC6B)")
cpp_quote("#define IXP_E_SMTP_452_NO_SYSTEM_STORAGE     HR_E(0xCC6C)")
cpp_quote("#define IXP_E_SMTP_552_STORAGE_OVERFLOW      HR_E(0xCC6D)")
cpp_quote("#define IXP_E_SMTP_553_MAILBOX_NAME_SYNTAX   HR_E(0xCC6E)")
cpp_quote("#define IXP_E_SMTP_554_TRANSACT_FAILED       HR_E(0xCC6F)")

/* SMTP Success Statuses */
cpp_quote("#define IXP_E_SMTP_211_SYSTEM_STATUS         HR_S(0xCC70)")
cpp_quote("#define IXP_E_SMTP_214_HELP_MESSAGE          HR_S(0xCC71)")
cpp_quote("#define IXP_E_SMTP_220_READY                 HR_S(0xCC72)")
cpp_quote("#define IXP_E_SMTP_221_CLOSING               HR_S(0xCC73)")
cpp_quote("#define IXP_E_SMTP_250_MAIL_ACTION_OKAY      HR_S(0xCC74)")
cpp_quote("#define IXP_E_SMTP_251_FORWARDING_MAIL       HR_S(0xCC75)")
cpp_quote("#define IXP_E_SMTP_354_START_MAIL_INPUT      HR_S(0xCC76)")
cpp_quote("#define IXP_E_SMTP_CONTINUE                  HR_S(0xCC77)")
cpp_quote("#define IXP_E_SMTP_334_AUTH_READY_RESPONSE   HR_S(0xCC78)")
cpp_quote("#define IXP_E_SMTP_245_AUTH_SUCCESS          HR_S(0xCC79)")

/* More SMTP Failure Statuses */
cpp_quote("#define IXP_E_SMTP_REJECTED_SENDER           HR_E(0xCC78)")
cpp_quote("#define IXP_E_SMTP_REJECTED_RECIPIENTS       HR_E(0xCC79)")
cpp_quote("#define IXP_E_SMTP_NO_SENDER                 HR_E(0xCC7A)")
cpp_quote("#define IXP_E_SMTP_NO_RECIPIENTS             HR_E(0xCC7B)")
cpp_quote("#define IXP_E_SMTP_530_STARTTLS_REQUIRED     HR_E(0xCC7C)")
cpp_quote("#define IXP_E_SMTP_NO_STARTTLS_SUPPORT       HR_E(0xCC7D)")
cpp_quote("#define IXP_E_SMTP_NO_DSN_SUPPORT            HR_E(0xCC7E)")
cpp_quote("#define IXP_E_SMTP_454_STARTTLS_FAILED       HR_E(0xCC7F)")

const SHORT CCHMAX_DOMAIN = 256;
const SHORT CCHMAX_PHONE_NUMBER = 128;

const DWORD DEFAULT_IMAP_PORT = 143;
const DWORD DEFAULT_POP3_PORT = 110;
const DWORD DEFAULT_SMTP_PORT = 25;
const DWORD DEFAULT_NNTP_PORT = 119;

typedef enum tagINETADDRTYPE
{
    ADDR_TO,
    ADDR_FROM,
    ADDR_DSN_NEVER = 16,
    ADDR_DSN_SUCCESS = 32,
    ADDR_DSN_FAILURE = 64,
    ADDR_DSN_DELAY = 128
} INETADDRTYPE;

const DWORD ADDR_TOFROM_MASK = 0x1;
const DWORD ADDR_DSN_MASK = 0xf0;

typedef enum tagDSNRET
{
    DSNRET_DEFAULT,
    DSNRET_HDRS,
    DSNRET_FULL,
} DSNRET;

typedef struct tagINETADDR
{
    INETADDRTYPE addrtype;
    CHAR szEmail[CCHMAX_EMAIL_ADDRESS];
} INETADDR, *LPINETADDR;

typedef struct tagINETADDRLIST
{
    ULONG cAddress;
    LPINETADDR prgAddress;
} INETADDRLIST, *LPINETADDRLIST;

typedef enum tagRASCONNTYPE
{
    RAS_CONNECT_LAN,
    RAS_CONNECT_MANUAL,
    RAS_CONNECT_RAS
} RASCONNTYPE;

typedef enum tagHTTPMAILPROPTYPE
{
    HTTPMAIL_PROP_INVALID,
    HTTPMAIL_PROP_ADBAR,
    HTTPMAIL_PROP_CONTACTS,
    HTTPMAIL_PROP_INBOX,
    HTTPMAIL_PROP_OUTBOX,
    HTTPMAIL_PROP_SENDMSG,
    HTTPMAIL_PROP_SENTITEMS,
    HTTPMAIL_PROP_DELETEDITEMS,
    HTTPMAIL_PROP_DRAFTS,
    HTTPMAIL_PROP_MSGFOLDERROOT,
    HTTPMAIL_PROP_SIG,
    HTTPMAIL_PROP_LAST
} HTTPMAILPROPTYPE;

typedef enum tagHTTPMAILSPECIALFOLDER
{
    HTTPMAIL_SF_NONE,
    HTTPMAIL_SF_UNRECOGNIZED,
    HTTPMAIL_SF_INBOX,
    HTTPMAIL_SF_DELETEDITEMS,
    HTTPMAIL_SF_DRAFTS,
    HTTPMAIL_SF_OUTBOX,
    HTTPMAIL_SF_SENTITEMS,
    HTTPMAIL_SF_CONTACTS,
    HTTPMAIL_SF_CALENDAR,
    HTTPMAIL_SF_MSNPROMO,
    HTTPMAIL_SF_LAST
} HTTPMAILSPECIALFOLDER;

typedef enum tagHTTPMAILCONTACTTYPE
{
    HTTPMAIL_CT_CONTACT,
    HTTPMAIL_CT_GROUP,
    HTTPMAIL_CT_LAST
} HTTPMAILCONTACTTYPE;

const DWORD DAVNAMESPACE_UNKNOWN = 0xFFFFFFFF;
const DWORD DAVNAMESPACE_DAV = 0;
const DWORD DAVNAMESPACE_HOTMAIL = 1;
const DWORD DAVNAMESPACE_HTTPMAIL = 2;
const DWORD DAVNAMESPACE_MAIL = 3;
const DWORD DAVNAMESPACE_CONTACTS = 4;

cpp_quote("#define ISF_SMTP_USEIPFORHELO        0x01")
cpp_quote("#define ISF_ALWAYSPROMPTFORPASSWORD  0x02")
/* for SMTP - send EHLO and use STARTTLS if available: */
cpp_quote("#define ISF_SSLONSAMEPORT            0x04")
cpp_quote("#define ISF_QUERYDSNSUPPORT          0x08")
/* for SMTP - send EHLO and use AUTH if available: */
cpp_quote("#define ISF_QUERYAUTHSUPPORT         0x10")

typedef struct INETSERVER
{
    CHAR szAccount[CCHMAX_ACCOUNT_NAME];
    CHAR szUserName[CCHMAX_USERNAME];
    CHAR szPassword[CCHMAX_PASSWORD];
    CHAR szServerName[CCHMAX_SERVER_NAME];
    CHAR szConnectoid[CCHMAX_CONNECTOID];
    RASCONNTYPE rasconntype;
    DWORD dwPort;
    BOOL fSSL;
    BOOL fTrySicily;
    DWORD dwTimeout;
    DWORD dwFlags;
} INETSERVER, *LPINETSERVER;

typedef enum tagIXPTYPE
{
    IXP_NNTP,
    IXP_SMTP,
    IXP_POP3,
    IXP_IMAP,
    IXP_RAS,
    IXP_HTTPMail
} IXPTYPE;

typedef enum tagIXPSTATUS
{
    IXP_FINDINGHOST,
    IXP_CONNECTING,
    IXP_SECURING,
    IXP_CONNECTED,
    IXP_AUTHORIZING,
    IXP_AUTHRETRY,
    IXP_AUTHORIZED,
    IXP_DISCONNECTING,
    IXP_DISCONNECTED,
    IXP_LAST
} IXPSTATUS;

const DWORD DEPTH_INFINITY = 0xFFFFFFFE;

typedef DWORD MEMBERINFOFLAGS;

const MEMBERINFOFLAGS HTTP_MEMBERINFO_COMMONPROPS = 0x0;
const MEMBERINFOFLAGS HTTP_MEMBERINFO_FOLDERPROPS = 0x1;
const MEMBERINFOFLAGS HTTP_MEMBERINFO_MESSAGEPROPS = 0x2;
const MEMBERINFOFLAGS HTTP_MEMBERINFO_ALLPROPS = HTTP_MEMBERINFO_FOLDERPROPS | HTTP_MEMBERINFO_MESSAGEPROPS;

typedef DWORD IMAP_MSGFLAGS;

const IMAP_MSGFLAGS IMAP_MSG_NOFLAGS = 0x00;
const IMAP_MSGFLAGS IMAP_MSG_ANSWERED = 0x01;
const IMAP_MSGFLAGS IMAP_MSG_FLAGGED = 0x02;
const IMAP_MSGFLAGS IMAP_MSG_DELETED = 0x04;
const IMAP_MSGFLAGS IMAP_MSG_SEEN = 0x08;
const IMAP_MSGFLAGS IMAP_MSG_DRAFT = 0x10;
const IMAP_MSGFLAGS IMAP_MSG_ALLFLAGS = 0x1f;

[
    object,
    uuid(CA30F3FF-C9AC-11D1-9A3A-00C04FA309D4),
    local
]
interface ITransportCallbackService : IUnknown
{
    HRESULT GetParentWindow(
        [in]    DWORD dwReserved,
        [out]   HWND *phwndParent);

    HRESULT GetAccount(
        [out]   LPDWORD pdwServerType,
        [out]   IImnAccount **ppAccount);
}

[
    object,
    uuid(0DF2C7E1-3435-11D0-81D0-00C04FD85AB4),
    local
]
interface ITransportCallback : IUnknown
{
    typedef struct tagIXPRESULT
    {
        HRESULT hrResult;
        LPSTR pszResponse;
        UINT uiServerError;
        HRESULT hrServerError;
        DWORD dwSocketError;
        LPSTR pszProblem;
    } IXPRESULT, *LPIXPRESULT;

    typedef enum tagCMDTYPE
    {
        CMD_SEND,
        CMD_RESP
    } CMDTYPE;

    HRESULT OnTimeout(
        [in,out]    DWORD *pdwTimeout,
        [in]        IInternetTransport *pTransport);

    HRESULT OnLogonPrompt(
        [in,out]    LPINETSERVER pInetServer,
        [in]        IInternetTransport *pTransport);

    INT OnPrompt(
        [in]    HRESULT hrError,
        [in]    LPCSTR pszText,
        [in]    LPCSTR pszCaption,
        [in]    UINT uType,
        [in]    IInternetTransport *pTransport);

    HRESULT OnStatus(
        [in]    IXPSTATUS ixpstatus,
        [in]    IInternetTransport *pTransport);

    HRESULT OnError(
        [in]    IXPSTATUS ixpstatus,
        [in]    LPIXPRESULT pResult,
        [in]    IInternetTransport *pTransport);

    HRESULT OnCommand(
        [in]    CMDTYPE cmdtype,
        [in]    LPSTR pszLine,
        [in]    HRESULT hrResponse,
        [in]    IInternetTransport *pTransport);
}

[
    object,
    uuid(1F636C01-364E-11D0-81D3-00C04FD85AB4),
    local
]
interface IInternetTransport : IUnknown
{
    const boolean iitAUTHENTICATE = TRUE;
    const boolean iitDONT_AUTHENTICATe = FALSE;
    const boolean iitENABLE_ONCOMMAND = TRUE;
    const boolean iitDISABLE_ONCOMMAND = FALSE;

    typedef enum tagIXPISSTATE
    {
        IXP_IS_CONNECTED,
        IXP_IS_BUSY,
        IXP_IS_READY,
        IXP_IS_AUTHENTICATED
    } IXPISSTATE;

    HRESULT GetServerInfo(
        [in,out]    LPINETSERVER pInetServer);

    IXPTYPE GetIXPType();

    HRESULT IsState(
        [in]    IXPISSTATE isstate);

    HRESULT InetServerFromAccount(
        [in]        IImnAccount *pAccount,
        [in,out]    LPINETSERVER pInetServer);

    HRESULT Connect(
        [in]    LPINETSERVER pInetServer,
        [in]    boolean fAuthenticate,
        [in]    boolean fCommandLogging);

    HRESULT HandsOffCallback();

    HRESULT Disconnect();

    HRESULT DropConnection();

    HRESULT GetStatus(
        [out]   IXPSTATUS *pCurrentStatus);
}

[
    object,
    uuid(1F636C02-364E-11D0-81D3-00C04FD85AB4),
    local
]
interface ISMTPCallback : ITransportCallback
{
    typedef enum tagSMTPCOMMAND
    {
        SMTP_NONE,
        SMTP_BANNER,
        SMTP_CONNECTED,
        SMTP_SEND_MESSAGE,
        SMTP_AUTH,
        SMTP_EHLO,
        SMTP_HELO,
        SMTP_MAIL,
        SMTP_RCPT,
        SMTP_RSET,
        SMTP_QUIT,
        SMTP_DATA,
        SMTP_DOT,
        SMTP_SEND_STREAM,
        SMTP_CUSTOM
    } SMTPCOMMAND;

    typedef struct tagSMTPSTREAM
    {
        DWORD cbIncrement;
        DWORD cbCurrent;
        DWORD cbTotal;
    } SMTPSTREAM, *LPSMTPSTREAM;

    typedef struct tagSMTPRESPONSE
    {
        SMTPCOMMAND command;
        BOOL fDone;
        IXPRESULT rIxpResult;
        ISMTPTransport *pTransport;

        [switch_type(SMTPCOMMAND), switch_is(command)]
        union
        {
        [case(SMTP_SEND_STREAM)]    SMTPSTREAM rStreamInfo;
        [default];
        } DUMMYUNIONNAME;
    } SMTPRESPONSE, *LPSMTPRESPONSE;

    HRESULT OnResponse(
        [in] LPSMTPRESPONSE pResponse);
}

[
    object,
    uuid(0DF2C7E2-3435-11D0-81D0-00C04FD85AB4),
    local
]
interface ISMTPTransport : IInternetTransport
{
    typedef struct tagSMTPMESSAGE
    {
        ULONG cbSize;
        LPSTREAM pstmMsg;
        INETADDRLIST rAddressList;
    } SMTPMESSAGE, *LPSMTPMESSAGE;

    HRESULT InitNew(
        [in]    LPSTR pszLogFilePath,
        [in]    ISMTPCallback *pCallback);

cpp_quote("#ifdef WINE_NO_UNICODE_MACROS")
cpp_quote("#undef SendMessage")
cpp_quote("#endif")

    HRESULT SendMessage(
        [in]    LPSMTPMESSAGE pMessage);

    HRESULT CommandMAIL(
        [in]    LPSTR pszEmailFrom);

    HRESULT CommandRCPT(
        [in]    LPSTR pszEmailTo);

    HRESULT CommandEHLO();

    HRESULT CommandHELO();

    HRESULT CommandAUTH(
        [in]    LPSTR pszAuthType);

    HRESULT CommandQUIT();

    HRESULT CommandRSET();

    HRESULT CommandDATA();

    HRESULT CommandDOT();

    HRESULT SendDataStream(
        [in]    IStream *pStream,
        [in]    ULONG cbSize);
}

[
    object,
    uuid(0DF2C7EC-3435-11D0-81D0-00C04FD85AB4),
    local
]
interface ISMTPTransport2 : ISMTPTransport
{
    typedef struct tagSMTPMESSAGE2
    {
        SMTPMESSAGE smtpMsg;
        LPSTR pszDSNENVID;
        DSNRET dsnRet;
        DWORD dwReserved;
        DWORD dwReserved2;
    } SMTPMESSAGE2, *LPSMTPMESSAGE2;

    HRESULT SetWindow();

    HRESULT ResetWindow();

    HRESULT SendMessage2(
        [in]    LPSMTPMESSAGE2 pMessage);

    HRESULT CommandRCPT2(
        [in]    LPSTR pszEmailTo,
        [in]    INETADDRTYPE atDSN);
}

/* FIXME: IDAVNamespaceArbiter, IPropPatchRequest, IPropFindRequest, IPropFindMultiResponse, IPropFindResponse, IHTTPMailCallback, IHTTPMailTransport */

[
    object,
    uuid(0DF2C7E3-3435-11D0-81D0-00C04FD85AB4),
    local
]
interface IPOP3Callback : ITransportCallback
{
    typedef enum tagPOP3COMMAND
    {
        POP3_NONE,
        POP3_BANNER,
        POP3_CONNECTED,
        POP3_USER,
        POP3_PASS,
        POP3_AUTH,
        POP3_UIDL,
        POP3_STAT,
        POP3_LIST,
        POP3_DELE,
        POP3_RETR,
        POP3_TOP,
        POP3_NOOP,
        POP3_QUIT,
        POP3_RSET,
        POP3_CUSTOM
    } POP3COMMAND;

    typedef struct tagPOP3RETR
    {
        BOOL fHeader;
        BOOL fBody;
        DWORD dwPopId;
        DWORD cbSoFar;
        LPSTR pszLines;
        ULONG cbLines;
    } POP3RETR, *LPPOP3RETR;

    typedef struct tagPOP3TOP
    {
        BOOL fHeader;
        BOOL fBody;
        DWORD dwPopId;
        DWORD cPreviewLines;
        DWORD cbSoFar;
        LPSTR pszLines;
        ULONG cbLines;
    } POP3TOP, *LPPOP3TOP;

    typedef struct tagPOP3LIST
    {
        DWORD dwPopId;
        DWORD cbSize;
    } POP3LIST, *LPPOP3LIST;

    typedef struct tagPOP3UIDL
    {
        DWORD dwPopId;
        LPSTR pszUidl;
    } POP3UIDL, *LPPOP3UIDL;

    typedef struct tagPOP3STAT
    {
        DWORD cMessages;
        DWORD cbMessages;
    } POP3STAT, *LPPOP3STAT;

    typedef struct tagPOP3RESPONSE
    {
        POP3COMMAND command;
        BOOL fDone;
        IXPRESULT rIxpResult;
        IPOP3Transport *pTransport;
        BOOL fValidInfo;
        [switch_type(POP3COMMAND), switch_is(command)]
        union
        {
        [case(POP3_UIDL)] POP3UIDL rUidlInfo;
        [case(POP3_STAT)] POP3STAT rStatInfo;
        [case(POP3_LIST)] POP3LIST rListInfo;
        [case(POP3_DELE)] DWORD dwPopId;
        [case(POP3_RETR)] POP3RETR rRetrInfo;
        [case(POP3_TOP)]  POP3TOP rTopInfo;
        [default];
        } DUMMYUNIONNAME;
    } POP3RESPONSE, *LPPOP3RESPONSE;

    HRESULT OnResponse(
        [in]    LPPOP3RESPONSE pResponse);
}

[
    object,
    uuid(0DF2C7E4-3435-11D0-81D0-00C04FD85AB4),
    local
]
interface IPOP3Transport : IInternetTransport
{
    typedef enum tagPOP3CMDTYPE
    {
        POP3CMD_GET_POPID,
        POP3CMD_GET_MARKED,
        POP3CMD_GET_ALL
    } POP3CMDTYPE;

    typedef enum tagPOP3MARKTYPE
    {
        POP3_MARK_FOR_TOP = 0x01,
        POP3_MARK_FOR_RETR = 0x02,
        POP3_MARK_FOR_DELE = 0x04,
        POP3_MARK_FOR_UIDL = 0x08,
        POP3_MARK_FOR_LIST = 0x10
    } POP3MARKTYPE;

    HRESULT InitNew(
        [in]    LPSTR pszLogFilePath,
        [in]    IPOP3Callback *pCallback);

    HRESULT MarkItem(
        [in]    POP3MARKTYPE marktype,
        [in]    DWORD dwPopId,
        [in]    boolean fMarked);

    HRESULT CommandAUTH(
        [in]    LPSTR pszAuthType);

    HRESULT CommandUSER(
        [in]    LPSTR pszUserName);

    HRESULT CommandPASS(
        [in]    LPSTR pszPassword);

    HRESULT CommandLIST(
        [in]    POP3CMDTYPE cmdtype,
        [in]    DWORD dwPopId);

    HRESULT CommandTOP(
        [in]    POP3CMDTYPE cmdtype,
        [in]    DWORD dwPopId,
        [in]    DWORD cPreviewLines);

    HRESULT CommandQUIT();

    HRESULT CommandSTAT();

    HRESULT CommandNOOP();

    HRESULT CommandRSET();

    HRESULT CommandUIDL(
        [in]    POP3CMDTYPE cmdtype,
        [in]    DWORD dwPopId);

    HRESULT CommandDELE(
        [in]    POP3CMDTYPE cmdtype,
        [in]    DWORD dwPopId);

    HRESULT CommandRETR(
        [in]    POP3CMDTYPE cmdtype,
        [in]    DWORD dwPopId);
}

/* FIXME: INNTPCallback, INNTPTransport */

[
    object,
    uuid(8C438160-4EF6-11d0-874F-00AA00530EE9),
    local,
]
interface IRangeList : IUnknown
{
    const ULONG RL_RANGE_ERROR = ((ULONG)-1);
    const ULONG RL_LAST_MESSAGE = ((ULONG)-1);

    HRESULT Clear();

    HRESULT IsInRange(
        [in]    const ULONG value);

    HRESULT Min(
        [out]   ULONG *pulMin);

    HRESULT Max(
        [out]   ULONG *pulMax);

    HRESULT Save(
        [out]   byte **ppbDestination,
        [out]   ULONG *pulSizeOfDestination);

    HRESULT Load(
        [in, size_is(ulSizeOfSource)]   byte *pbSource,
        [in]    const ULONG ulSizeOfSource);

    HRESULT AddRange(
        [in]    const ULONG low,
        [in]    const ULONG high);

    HRESULT AddSingleValue(
        [in]    const ULONG value);

    HRESULT AddRangeList(
        [in]    const IRangeList *prl);

    HRESULT DeleteRange(
        [in]    const ULONG low,
        [in]    const ULONG high);

    HRESULT DeleteSingleValue(
        [in]    const ULONG value);

    HRESULT DeleteRangeList(
        [in]    const IRangeList *prl);

    HRESULT MinOfRange(
        [in]    const ULONG value,
        [out]   ULONG *pulMinOfRange);

    HRESULT MaxOfRange(
        [in]    const ULONG value,
        [out]   ULONG *pulMaxOfRange);

    HRESULT RangeToIMAPString(
        [out]   LPSTR *ppszDestination,
        [out]   LPDWORD pdwLengthOfDestination);

    HRESULT Next(
        [in]    const ULONG current,
        [out]   ULONG *pulNext);

    HRESULT Prev(
        [in]    const ULONG current,
        [out]   ULONG *pulPrev);

    HRESULT Cardinality(
        [out]   ULONG *pulCardinality);

    HRESULT CardinalityFrom(
        [in]    const ULONG ulStartPoint,
        [out]   ULONG *pulCardinalityFrom);
}

[
    object,
    uuid(E9E9D8A3-4EDD-11d0-874F-00AA00530EE9),
    local
]
interface IIMAPCallback : ITransportCallback
{
    typedef DWORD IMAP_MBOXFLAGS;
    const IMAP_MBOXFLAGS IMAP_MBOX_NOFLAGS = 0x0;
    const IMAP_MBOXFLAGS IMAP_MBOX_MARKED = 0x1;
    const IMAP_MBOXFLAGS IMAP_MBOX_NOINFERIORS = 0x2;
    const IMAP_MBOXFLAGS IMAP_MBOX_NOSELECT = 0x4;
    const IMAP_MBOXFLAGS IMAP_MBOX_UNMARKED = 0x8;
    const IMAP_MBOXFLAGS IMAP_MBOX_ALLFLAGS = 0xf;

    typedef enum tagIMAP_RESPONSE_TYPE
    {
        irtERROR_NOTIFICATION,
        irtCOMMAND_COMPLETION,
        irtSERVER_ALERT,
        irtPARSE_ERROR,
        irtMAILBOX_UPDATE,
        irtDELETED_MSG,
        irtFETCH_BODY,
        irtUPDATE_MSG,
        irtAPPLICABLE_FLAGS,
        irtPERMANENT_FLAGS,
        irtUIDVALIDITY,
        irtREADWRITE_STATUS,
        irtTRYCREATE,
        irtSEARCH,
        irtMAILBOX_LISTING,
        irtMAILBOX_STATUS,
        irtAPPEND_PROGRESS,
        irtUPDATE_MSG_EX
    } IMAP_RESPONSE_TYPE;

    typedef struct tagFETCH_BODY_PART
    {
        DWORD dwMsgSeqNum;
        LPSTR pszBodyTag;
        DWORD dwTotalBytes;
        DWORD dwSizeOfData;
        DWORD dwOffset;
        BOOL fDone;
        LPSTR pszData;
        LPARAM lpFetchCookie1;
        LPARAM lpFetchCookie2;
    } FETCH_BODY_PART;

    typedef struct tagFETCH_CMD_RESULTS
    {
        DWORD dwMsgSeqNum;
        BOOL bMsgFlags;
        IMAP_MSGFLAGS mfMsgFlags;
        BOOL bRFC822Size;
        DWORD dwRFC822Size;
        BOOL bUID;
        DWORD dwUID;
        BOOL bInternalDate;
        FILETIME ftInternalDate;
        LPARAM lpFetchCookie1;
        LPARAM lpFetchCookie2;
    } FETCH_CMD_RESULTS;

    typedef struct tagIMAPADDR
    {
        LPSTR pszName;
        LPSTR pszADL;
        LPSTR pszMailbox;
        LPSTR pszHost;
        struct tagIMAPADDR *pNext;
    } IMAPADDR;

    typedef struct tagFETCH_CMD_RESULTS_EX
    {
        DWORD dwMsgSeqNum;
        BOOL bMsgFlags;
        IMAP_MSGFLAGS mfMsgFlags;
        BOOL bRFC822Size;
        DWORD dwRFC822Size;
        BOOL bUID;
        DWORD dwUID;
        BOOL bInternalDate;
        FILETIME ftInternalDate;
        LPARAM lpFetchCookie1;
        LPARAM lpFetchCookie2;
        BOOL bEnvelope;
        FILETIME ftENVDate;
        LPSTR pszENVSubject;
        IMAPADDR *piaENVFrom;
        IMAPADDR *piaENVSender;
        IMAPADDR *piaENVReplyTo;
        IMAPADDR *piaENVTo;
        IMAPADDR *piaENVCc;
        IMAPADDR *piaENVBcc;
        LPSTR pszENVInReplyTo;
        LPSTR pszENVMessageID;
        DWORD dwReserved1;
        DWORD dwReserved2;
        DWORD dwReserved3;
    } FETCH_CMD_RESULTS_EX;

    typedef struct tagMBOX_MSGCOUNT
    {
        BOOL bGotExistsResponse;
        DWORD dwExists;
        BOOL bGotRecentResponse;
        DWORD dwRecent;
        BOOL bGotUnseenResponse;
        DWORD dwUnseen;
    } MBOX_MSGCOUNT;

    typedef struct tagIMAP_LISTLSUB_RESPONSE
    {
        LPSTR pszMailboxName;
        IMAP_MBOXFLAGS imfMboxFlags;
        char cHierarchyChar;
    } IMAP_LISTLSUB_RESPONSE;

    typedef struct tagIMAP_STATUS_RESPONSE
    {
        LPSTR pszMailboxName;
        BOOL fMessages;
        DWORD dwMessages;
        BOOL fRecent;
        DWORD dwRecent;
        BOOL fUIDNext;
        DWORD dwUIDNext;
        BOOL fUIDValidity;
        DWORD dwUIDValidity;
        BOOL fUnseen;
        DWORD dwUnseen;
    } IMAP_STATUS_RESPONSE;

    typedef struct tagAPPEND_PROGRESS
    {
        DWORD dwUploaded;
        DWORD dwTotal;
    } APPEND_PROGRESS;

    typedef [switch_type(IMAP_RESPONSE_TYPE)] union tagIMAP_RESPONSE_DATA
    {
        [case (irtMAILBOX_UPDATE)] MBOX_MSGCOUNT *pmcMsgCount;
        [case (irtDELETED_MSG)] DWORD dwDeletedMsgSeqNum;
        [case (irtFETCH_BODY)] FETCH_BODY_PART *pFetchBodyPart;
        [case (irtUPDATE_MSG)] FETCH_CMD_RESULTS *pFetchResults;
        [case (irtAPPLICABLE_FLAGS, irtPERMANENT_FLAGS)] IMAP_MSGFLAGS imfImapMessageFlags;
        [case (irtUIDVALIDITY)] DWORD dwUIDValidity;
        [case (irtREADWRITE_STATUS)] BOOL bReadWrite;
        [case (irtSEARCH)] IRangeList *prlSearchResults;
        [case (irtMAILBOX_LISTING)] IMAP_LISTLSUB_RESPONSE illrdMailboxListing;
        [case (irtMAILBOX_STATUS)] IMAP_STATUS_RESPONSE *pisrStatusResponse;
        [case (irtAPPEND_PROGRESS)] APPEND_PROGRESS *papAppendProgress;
        [case (irtUPDATE_MSG_EX)] FETCH_CMD_RESULTS_EX *pFetchResultsEx;
    } IMAP_RESPONSE_DATA;

    typedef struct tagIMAP_RESPONSE
    {
        WPARAM wParam;
        LPARAM lParam;
        HRESULT hrResult;
        LPSTR lpszResponseText;
        IMAP_RESPONSE_TYPE irtResponseType;
        [switch_is(irtResponseType)] IMAP_RESPONSE_DATA irdResponseData;
    } IMAP_RESPONSE;

    HRESULT OnResponse([in] const IMAP_RESPONSE *pirIMAPResponse);
}

[
object,
uuid(E9E9D8A8-4EDD-11d0-874F-00AA00530EE9),
local,
]
interface IIMAPTransport : IInternetTransport
{
    const DWORD IMAP_CAPABILITY_IMAP4 = 0x1;
    const DWORD IMAP_CAPABILITY_IMAP4rev1 = 0x2;
    const DWORD IMAP_CAPABILITY_IDLE = 0x4;
    const DWORD IMAP_CAPABILITY_ALLFLAGS = 0x7;

    HRESULT InitNew(
        [in]    LPSTR pszLogFilePath,
        [in]    IIMAPCallback *pCBHandler);

    HRESULT NewIRangeList(
        [out]   IRangeList **pprlNewRangeList);

    HRESULT Capability(
        [out]   DWORD *pdwCapabilityFlags);

    HRESULT Select(
        [in]    WPARAM wParam,
        [in]    LPARAM lParam,
        [in]    IIMAPCallback *pCBHandler,
        [in]    LPSTR lpszMailboxName);

    HRESULT Examine(
        [in]    WPARAM wParam,
        [in]    LPARAM lParam,
        [in]    IIMAPCallback *pCBHandler,
        [in]    LPSTR lpszMailboxName);

    HRESULT Create(
        [in]    WPARAM wParam,
        [in]    LPARAM lParam,
        [in]    IIMAPCallback *pCBHandler,
        [in]    LPSTR lpszMailboxName);

    HRESULT Delete(
        [in]    WPARAM wParam,
        [in]    LPARAM lParam,
        [in]    IIMAPCallback *pCBHandler,
        [in]    LPSTR lpszMailboxName);

    HRESULT Rename(
        [in]    WPARAM wParam,
        [in]    LPARAM lParam,
        [in]    IIMAPCallback *pCBHandler,
        [in]    LPSTR lpszMailboxName,
        [in]    LPSTR lpszNewMailboxName);

    HRESULT Subscribe(
        [in]    WPARAM wParam,
        [in]    LPARAM lParam,
        [in]    IIMAPCallback *pCBHandler,
        [in]    LPSTR lpszMailboxName);

    HRESULT Unsubscribe(
        [in]    WPARAM wParam,
        [in]    LPARAM lParam,
        [in]    IIMAPCallback *pCBHandler,
        [in]    LPSTR lpszMailboxName);

    HRESULT List(
        [in]    WPARAM wParam,
        [in]    LPARAM lParam,
        [in]    IIMAPCallback *pCBHandler,
        [in]    LPSTR lpszMailboxNameReference,
        [in]    LPSTR lpszMailboxNamePattern);

    HRESULT Lsub(
        [in]    WPARAM wParam,
        [in]    LPARAM lParam,
        [in]    IIMAPCallback *pCBHandler,
        [in]    LPSTR lpszMailboxNameReference,
        [in]    LPSTR lpszMailboxNamePattern);

    HRESULT Append(
        [in]    WPARAM wParam,
        [in]    LPARAM lParam,
        [in]    IIMAPCallback *pCBHandler,
        [in]    LPSTR lpszMailboxName,
        [in]    LPSTR lpszMessageFlags,
        [in]    FILETIME ftMessageDateTime,
        [in]    LPSTREAM lpstmMessageToSave);

    HRESULT Close(
        [in]    WPARAM wParam,
        [in]    LPARAM lParam,
        [in]    IIMAPCallback *pCBHandler);

    HRESULT Expunge(
        [in]    WPARAM wParam,
        [in]    LPARAM lParam,
        [in]    IIMAPCallback *pCBHandler);

    HRESULT Search(
        [in]    WPARAM wParam,
        [in]    LPARAM lParam,
        [in]    IIMAPCallback *pCBHandler,
        [in]    LPSTR lpszSearchCriteria,
        [in]    boolean bReturnUIDs,
        [in]    IRangeList *pMsgRange,
        [in]    boolean bUIDRangeList);

    HRESULT Fetch(
        [in]    WPARAM wParam,
        [in]    LPARAM lParam,
        [in]    IIMAPCallback *pCBHandler,
        [in]    IRangeList *pMsgRange,
        [in]    boolean bUIDMsgRange,
        [in]    LPSTR lpszFetchArgs);

    HRESULT Store(
        [in]    WPARAM wParam,
        [in]    LPARAM lParam,
        [in]    IIMAPCallback *pCBHandler,
        [in]    IRangeList *pMsgRange,
        [in]    boolean bUIDRangeList,
        [in]    LPSTR lpszStoreArgs);

    HRESULT Copy(
        [in]    WPARAM wParam,
        [in]    LPARAM lParam,
        [in]    IIMAPCallback *pCBHandler,
        [in]    IRangeList *pMsgRange,
        [in]    boolean bUIDRangeList,
        [in]    LPSTR lpszMailboxName);

    HRESULT Noop(
        [in]    WPARAM wParam,
        [in]    LPARAM lParam,
        [in]    IIMAPCallback *pCBHandler);

    HRESULT ResizeMsgSeqNumTable(
        [in]    DWORD dwSizeOfMbox);

    HRESULT UpdateSeqNumToUID(
        [in]    DWORD dwMsgSeqNum,
        [in]    DWORD dwUID);

    HRESULT RemoveSequenceNum(
        [in]    DWORD dwDeletedMsgSeqNum);

    HRESULT MsgSeqNumToUID(
        [in]    DWORD dwMsgSeqNum,
        [out]   DWORD *pdwUID);

    HRESULT GetMsgSeqNumToUIDArray(
        [out]   DWORD **ppdwMsgSeqNumToUIDArray,
        [out]   DWORD *pdwNumberOfElements);

    HRESULT GetHighestMsgSeqNum(
        [out]   DWORD *pdwHighestMSN);

    HRESULT ResetMsgSeqNumToUID();

    HRESULT SetDefaultCBHandler(
        [in]    IIMAPCallback *pCBHandler);

    HRESULT Status(
        [in]    WPARAM wParam,
        [in]    LPARAM lParam,
        [in]    IIMAPCallback *pCBHandler,
        [in]    LPSTR pszMailboxName,
        [in]    LPSTR pszStatusCmdArgs);
}

#if 0
cpp_quote("HRESULT WINAPI CreateRASTransport(IRASTransport **ppTransport);")
cpp_quote("HRESULT WINAPI CreateNNTPTransport(INNTPTransport **ppTransport);")
cpp_quote("HRESULT WINAPI CreateIMAPTransport2(IIMAPTransport2 **ppTransport);")
#endif
cpp_quote("HRESULT WINAPI CreateRangeList(IRangeList **ppRangeList);")
cpp_quote("HRESULT WINAPI CreateSMTPTransport(ISMTPTransport **ppTransport);")
cpp_quote("HRESULT WINAPI CreatePOP3Transport(IPOP3Transport **ppTransport);")
cpp_quote("HRESULT WINAPI CreateIMAPTransport(IIMAPTransport **ppTransport);")