class CFile; enum UPLOAD_STATE { UPLOAD_STATE_CREATE_SESSION, UPLOAD_STATE_SEND_DATA, UPLOAD_STATE_GET_REPLY, UPLOAD_STATE_CLOSE_SESSION, UPLOAD_STATE_CLOSED, UPLOAD_STATE_CANCEL_SESSION, UPLOAD_STATE_CANCELLED }; struct UPLOAD_DATA { UPLOAD_STATE State; bool fSchedulable; GUID Protocol; StringHandle SessionId; StringHandle ReplyUrl; StringHandle HostId; DWORD HostIdFallbackTimeout; FILETIME HostIdNoProgressStartTime; //--------------------------- UPLOAD_DATA(); ~UPLOAD_DATA(); void Serialize( HANDLE hFile ); void Unserialize( HANDLE hFile ); void SetUploadState( UPLOAD_STATE NewState ); }; class Uploader /* This class handles a particular upload attempt, updating the upload state and the job progress data as appropriate. It uses the UPLOAD_DATA in a CUploadJob to determine the starting state. Then it runs the upload state machine until the job is complete or is interrupted. */ { public: Uploader( Downloader * dl, CNetworkInterface & net, CUploadJob * job, HANDLE Token, ITransferCallback * CallBacks, QMErrInfo & ErrorInfo ); ~Uploader(); void Transfer(); bool InTerminalState() { return (m_data.State == UPLOAD_STATE_CLOSED || m_data.State == UPLOAD_STATE_CANCELLED); } void SetState( UPLOAD_STATE state ) { m_data.State = state; } static void SetResult( QMErrInfo & err, ERROR_SOURCE source, ERROR_STYLE style, DWORD code, char * comment = 0 ); private: // // Uploader objects are created on the stack, so member data must be kept small (under 200 bytes on x86). // CNetworkInterface & m_Network; ITransferCallback * m_Callbacks; Downloader * m_Downloader; HANDLE m_Token; CUploadJob * m_job; CFile * m_file; BG_JOB_TYPE m_JobType; UPLOAD_DATA & m_data; auto_ptr m_UrlInfo; QMErrInfo & m_ErrorInfo; HANDLE m_hFile; DWORD m_ExpectedServerOffset; long m_Restarts; const CCredentialsContainer * m_Credentials; typedef void (Uploader::* RESPONSE_FN )( CBitsCommandRequest & request, DWORD result ); struct ResponseEntry { DWORD Code; RESPONSE_FN Fn; }; #pragma warning( disable:4200 ) struct ResponseTable { RESPONSE_FN DefaultFn; ResponseEntry Entries[]; }; static ResponseTable Ping_ResponseTable; static ResponseTable CreateSession_ResponseTable; static ResponseTable SendData_ResponseTable; static ResponseTable CloseSession_ResponseTable; static ResponseTable CancelSession_ResponseTable; #pragma warning( default:4200 ) //--------------------------------------------------------------------- auto_ptr ContactServer(); void AnalyzeResponse( CBitsCommandRequest & request, DWORD result, ResponseTable & table ); // // fns to send data to the server // void Ping(); void CreateSession(); void SendData(); void GetReply(); void CloseSession(); void CancelSession(); // // fns to react to server responses // void Ping_Success( CBitsCommandRequest & request, DWORD result ); void CreateSession_NewSession( CBitsCommandRequest & request, DWORD result ); void CreateSession_InProgress( CBitsCommandRequest & request, DWORD result ); void SendData_Success( CBitsCommandRequest & request, DWORD result ); void SendData_Failure( CBitsCommandRequest & request, DWORD result ); void CloseSession_Success( CBitsCommandRequest & request, DWORD result ); void CloseSession_Failure( CBitsCommandRequest & request, DWORD result ); void CancelSession_Success( CBitsCommandRequest & request, DWORD result ); void CancelSession_Failure( CBitsCommandRequest & request, DWORD result ); void GenericServerError( CBitsCommandRequest & request, DWORD result ); //-------------------------------------------------------------------- void ReadReplyData( CBitsCommandRequest & request, bool fKeep ); }; FILE_DOWNLOAD_RESULT CategorizeError( QMErrInfo & ErrInfo );