diff options
Diffstat (limited to 'tdeioslaves/imap4/imapparser.h')
-rw-r--r-- | tdeioslaves/imap4/imapparser.h | 504 |
1 files changed, 504 insertions, 0 deletions
diff --git a/tdeioslaves/imap4/imapparser.h b/tdeioslaves/imap4/imapparser.h new file mode 100644 index 000000000..623fc8f85 --- /dev/null +++ b/tdeioslaves/imap4/imapparser.h @@ -0,0 +1,504 @@ +#ifndef _IMAPPARSER_H +#define _IMAPPARSER_H +/********************************************************************** + * + * imapparser.h - IMAP4rev1 Parser + * Copyright (C) 2001-2002 Michael Haeckel <haeckel@kde.org> + * Copyright (C) 2000 s.carstens@gmx.de + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Send comments and bug fixes to s.carstens@gmx.de + * + *********************************************************************/ + +#include <tqstringlist.h> +#include <tqvaluelist.h> +#include <tqptrlist.h> +#include <tqasciidict.h> + +#include <tdeio/authinfo.h> +#include <tdeio/slavebase.h> + +#include "imaplist.h" +#include "imapcommand.h" +#include "imapinfo.h" + +#include "mailheader.h" + +class KURL; +class TQString; +class mailAddress; +class mimeHeader; + + +/** @brief a string used during parsing + * the string allows you to move the effective start of the string using + * str.pos++ and str.pos--. + * @bug it is possible to move past the beginning and end of the string + */ +class parseString +{ +public: + parseString() { pos = 0; } + char operator[](uint i) const { return data[i + pos]; } + bool isEmpty() const { return pos >= data.size(); } + TQCString cstr() const + { + if (pos >= data.size()) return TQCString(); + return TQCString(data.data() + pos, data.size() - pos + 1); + } + int find(char c, int index = 0) + { + int res = data.find(c, index + pos); + return (res == -1) ? res : (res - pos); + } + // Warning: does not check for going past end of "data" + void takeLeft(TQCString& dest, uint len) const + { + dest.resize(len + 1); + tqmemmove(dest.data(), data.data() + pos, len); + } + // Warning: does not check for going past end of "data" + void takeLeftNoResize(TQCString& dest, uint len) const + { + tqmemmove(dest.data(), data.data() + pos, len); + } + // Warning: does not check for going past end of "data" + void takeMid(TQCString& dest, uint start, uint len) const + { + dest.resize(len + 1); + tqmemmove(dest.data(), data.data() + pos + start, len); + } + // Warning: does not check for going past end of "data" + void takeMidNoResize(TQCString& dest, uint start, uint len) const + { + tqmemmove(dest.data(), data.data() + pos + start, len); + } + void clear() + { + data.resize(0); + pos = 0; + } + uint length() + { + if( pos < data.size() ) { + return data.size() - pos; + } else { + return 0; + } + } + void fromString(const TQString &s) + { + clear(); + data.duplicate(s.latin1(), s.length()); + } + TQByteArray data; + uint pos; +}; + +class imapCache +{ +public: + imapCache () + { + myHeader = NULL; + mySize = 0; + myFlags = 0; + myUid = 0; + } + + ~imapCache () + { + if (myHeader) delete myHeader; + } + + mailHeader *getHeader () + { + return myHeader; + } + void setHeader (mailHeader * inHeader) + { + myHeader = inHeader; + } + + ulong getSize () + { + return mySize; + } + void setSize (ulong inSize) + { + mySize = inSize; + } + + ulong getUid () + { + return myUid; + } + void setUid (ulong inUid) + { + myUid = inUid; + } + + ulong getFlags () + { + return myFlags; + } + void setFlags (ulong inFlags) + { + myFlags = inFlags; + } + + TQCString getDate () + { + return myDate; + } + void setDate (const TQCString & _str) + { + myDate = _str; + } + void clear() + { + if (myHeader) delete myHeader; + myHeader = NULL; + mySize = 0; + myFlags = 0; + myDate = TQCString(); + myUid = 0; + } + +protected: + mailHeader * myHeader; + ulong mySize; + ulong myFlags; + ulong myUid; + TQCString myDate; +}; + + +class imapParser +{ + +public: + + /** the different states the client can be in */ + enum IMAP_STATE + { + ISTATE_NO, /**< Not connected */ + ISTATE_CONNECT, /**< Connected but not logged in */ + ISTATE_LOGIN, /**< Logged in */ + ISTATE_SELECT /**< A folder is currently selected */ + }; + +public: + imapParser (); + virtual ~ imapParser (); + + /** @brief Get the current state */ + enum IMAP_STATE getState () { return currentState; } + /** @brief Set the current state */ + void setState(enum IMAP_STATE state) { currentState = state; } + + /* @brief return the currently selected mailbox */ + const TQString getCurrentBox () + { + return rfcDecoder::fromIMAP(currentBox); + }; + + /** + * @brief do setup and send the command to parseWriteLine + * @param aCmd The command to perform + * @return The completed command + */ + imapCommand *sendCommand (imapCommand * aCmd); + /** + * @brief perform a command and wait to parse the result + * @param aCmd The command to perform + * @return The completed command + */ + imapCommand *doCommand (imapCommand * aCmd); + + + /** + * @brief plaintext login + * @param aUser Username + * @param aPass Password + * @param resultInfo The resultinfo from the command + * @return success or failure + */ + bool clientLogin (const TQString & aUser, const TQString & aPass, TQString & resultInfo); + /** + * @brief non-plaintext login + * @param aUser Username + * @param aPass Password + * @param aAuth authentication method + * @param isSSL are we using SSL + * @param resultInfo The resultinfo from the command + * @return success or failure + */ + bool clientAuthenticate (TDEIO::SlaveBase *slave, TDEIO::AuthInfo &ai, const TQString & aFTQDN, + const TQString & aAuth, bool isSSL, TQString & resultInfo); + + /** + * main loop for the parser + * reads one line and dispatches it to the appropriate sub parser + */ + int parseLoop (); + + /** + * @brief parses all untagged responses and passes them on to the + * following parsers + */ + void parseUntagged (parseString & result); + + /** @brief parse a RECENT line */ + void parseRecent (ulong value, parseString & result); + /** @brief parse a RESULT line */ + void parseResult (TQByteArray & result, parseString & rest, + const TQString & command = TQString()); + /** @brief parse a CAPABILITY line */ + void parseCapability (parseString & result); + /** @brief parse a FLAGS line */ + void parseFlags (parseString & result); + /** @brief parse a LIST line */ + void parseList (parseString & result); + /** @brief parse a LSUB line */ + void parseLsub (parseString & result); + /** @brief parse a LISTRIGHTS line */ + void parseListRights (parseString & result); + /** @brief parse a MYRIGHTS line */ + void parseMyRights (parseString & result); + /** @brief parse a SEARCH line */ + void parseSearch (parseString & result); + /** @brief parse a STATUS line */ + void parsetStatus (parseString & result); + /** @brief parse a EXISTS line */ + void parseExists (ulong value, parseString & result); + /** @brief parse a EXPUNGE line */ + void parseExpunge (ulong value, parseString & result); + /** @brief parse a ACL line */ + void parseAcl (parseString & result); + /** @brief parse a ANNOTATION line */ + void parseAnnotation (parseString & result); + /** @brief parse a NAMESPACE line */ + void parseNamespace (parseString & result); + /** @brief parse a QUOTAROOT line */ + void parseQuotaRoot (parseString & result); + /** @brief parse a QUOTA line */ + void parseQuota (parseString & result); + /** @brief parse a custom command line */ + void parseCustom (parseString & result); + /** @brief parse a OTHER-USER line */ + void parseOtherUser (parseString & result); + /** @brief parse a DELEGATE line */ + void parseDelegate (parseString & result); + /** @brief parse a OUT-OF-OFFICE line */ + void parseOutOfOffice (parseString & result); + + /** + * parses the results of a fetch command + * processes it with the following sub parsers + */ + void parseFetch (ulong value, parseString & inWords); + + /** read a envelope from imap and parse the addresses */ + mailHeader *parseEnvelope (parseString & inWords); + /** @brief parse an address list and return a list of addresses */ + void parseAddressList (parseString & inWords, TQPtrList<mailAddress>& list); + /** @brief parse an address and return the ref again */ + const mailAddress& parseAddress (parseString & inWords, mailAddress& buffer); + + /** parse the result of the body command */ + void parseBody (parseString & inWords); + + /** parse the body structure recursively */ + mimeHeader *parseBodyStructure (parseString & inWords, + TQString & section, mimeHeader * inHeader = 0); + + /** parse only one not nested part */ + mimeHeader *parseSimplePart (parseString & inWords, TQString & section, + mimeHeader * localPart = 0); + + /** parse a parameter list (name value pairs) */ + TQAsciiDict < TQString > parseParameters (parseString & inWords); + + /** + * parse the disposition list (disposition (name value pairs)) + * the disposition has the key 'content-disposition' + */ + TQAsciiDict < TQString > parseDisposition (parseString & inWords); + + // reimplement these + + /** relay hook to send the fetched data directly to an upper level */ + virtual void parseRelay (const TQByteArray & buffer); + + /** relay hook to announce the fetched data directly to an upper level + */ + virtual void parseRelay (ulong); + + /** read at least len bytes */ + virtual bool parseRead (TQByteArray & buffer, ulong len, ulong relay = 0); + + /** read at least a line (up to CRLF) */ + virtual bool parseReadLine (TQByteArray & buffer, ulong relay = 0); + + /** write argument to server */ + virtual void parseWriteLine (const TQString &); + + // generic parser routines + + /** parse a parenthesized list */ + void parseSentence (parseString & inWords); + + /** parse a literal or word, may require more data */ + TQCString parseLiteralC(parseString & inWords, bool relay = false, + bool stopAtBracket = false, int *outlen = 0); + inline TQByteArray parseLiteral (parseString & inWords, bool relay = false, + bool stopAtBracket = false) { + int len = 0; // string size + // Choice: we can create an extra TQCString, or we can get the buffer in + // the wrong size to start. Let's try option b. + TQCString tmp = parseLiteralC(inWords, relay, stopAtBracket, &len); + return TQByteArray().duplicate(tmp.data(), len); + } + + // static parser routines, can be used elsewhere + + static TQCString b2c(const TQByteArray &ba) + { return TQCString(ba.data(), ba.size() + 1); } + + /** parse one word (maybe quoted) upto next space " ) ] } */ + static TQCString parseOneWordC (parseString & inWords, + bool stopAtBracket = FALSE, int *len = 0); + + /** parse one number using parseOneWord */ + static bool parseOneNumber (parseString & inWords, ulong & num); + + /** extract the box,section,list type, uid, uidvalidity,info from an url */ + static void parseURL (const KURL & _url, TQString & _box, TQString & _section, + TQString & _type, TQString & _uid, TQString & _validity, + TQString & _info); + + + /** @brief return the last handled foo + * @todo work out what a foo is + */ + imapCache *getLastHandled () + { + return lastHandled; + }; + +/** @brief return the last results */ + const TQStringList & getResults () + { + return lastResults; + }; + + /** @brief return the last status code */ + const imapInfo & geStatus () + { + return lasStatus; + }; + /** return the select info */ + const imapInfo & getSelected () + { + return selectInfo; + }; + + const TQByteArray & getContinuation () + { + return continuation; + }; + + /** @brief see if server has a capability */ + bool hasCapability (const TQString &); + + void removeCapability (const TQString & cap); + + static inline void skipWS (parseString & inWords) + { + char c; + while (!inWords.isEmpty() && + ((c = inWords[0]) == ' ' || c == '\t' || c == '\r' || c == '\n')) + { + inWords.pos++; + } + } + + /** @brief find the namespace for the given box */ + TQString namespaceForBox( const TQString & box ); + + +protected: + + /** the current state we're in */ + enum IMAP_STATE currentState; + + /** the box selected */ + TQString currentBox; + + /** @brief here we store the result from select/examine and unsolicited updates */ + imapInfo selectInfo; + + /** @brief the results from the last status command */ + imapInfo lasStatus; + + /** @brief the results from the capabilities, split at ' ' */ + TQStringList imapCapabilities; + + /** @brief the results from list/lsub/listrights commands */ + TQValueList < imapList > listResponses; + + /** @brief queues handling the running commands */ + TQPtrList < imapCommand > sentQueue; // no autodelete + TQPtrList < imapCommand > completeQueue; // autodelete !! + + /** + * everything we didn't handle, everything but the greeting is bogus + */ + TQStringList unhandled; + + /** the last continuation request (there MUST not be more than one pending) */ + TQByteArray continuation; + + /** the last uid seen while a fetch */ + TQString seenUid; + imapCache *lastHandled; + + ulong commandCounter; + + /** @brief the results from search/acl commands */ + TQStringList lastResults; + + /** + * @brief namespace prefix - delimiter association + * The namespace is cleaned before so that it does not contain the delimiter + */ + TQMap<TQString, TQString> namespaceToDelimiter; + + /** + * @brief list of namespaces in the form: section=namespace=delimiter + * section is 0 (personal), 1 (other users) or 2 (shared) + */ + TQStringList imapNamespaces; + +private: + + /** we don't want to be able to copy this object */ + imapParser & operator = (const imapParser &); // hide the copy ctor + +}; +#endif |