BLc @s*dZdZddkTddkZddkZddkZddkZddkZddkZddk Z ddk l Z l Z ddk lZddklZddklZd Zd ZeZeeeeeegZd Zd Zd Z e!Z"ei#dei$Z%de&fdYZ'de&fdYZ(dZ)dZ*dei+fdYZ,dfdYZ-dZ.dZ/de&fdYZ0dfdYZ1dfd YZ2d!fd"YZ3d#fd$YZ4d%fd&YZ5d'e6fd(YZ7d)e7fd*YZ8d+e7fd,YZ9d-e6fd.YZ:d/fd0YZ;d1fd2YZ<e=d3joddk>Z>dd4k?l?Z?ye>i@d5ZAWneBj oeCd6ZAnXe?d7ZDeCd8ZEe1eAeDd9eEZFd:GHyeFiGWn!e0j oZHd;eHiIGHnXd<GHeFiJZKeKeLZMeKeNZOeKePZQd=eMeOeQfGHeeFiRZSeZAxysd>GHx)eTeSD]\ZUZVd?eUeVfGHqWxJeA oAyeSeWeCd@ZAWn eXj oZYeYGHeZAnXqWeAejoeFiZeAe[Z\neFi]eAe[Z\e^e\ odAeAGHPneZAe^e\Z_dZ`xre\D]jZadBe^eaGHeaibGe^eaGeaicGHx9eaD]1ZddCGedibGedieGedifGedicGHe`d57Z`qWqWHdDGe_GHdEGe`GHWnegj oPnXqdFGHndS(Gs0.1.8ii(t*N(tloadtdump(tMIMEBase(tMIMEText(t MIMEMultiparts3https://www.google.com/accounts/ServiceLoginBoxAuths#https://mail.google.com/mail/?ui=1&tsdtdiis D\((.*?)\);t GmailErrorcBseZdZRS(s Exception thrown upon gmail-specific failures, in particular a failure to log in and a failure to parse responses. (t__name__t __module__t__doc__(((s3/home/beckel/datasingularity.com/Texter/libgmail.pyRCstGmailSendErrorcBseZdZRS(s> Exception to throw if we're unable to send a message (R R R (((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR Ksc s|i}dig}|D])}|o|dd jo ||qq~}eidd|}gy%|hdd6hfd d6UWn#ej o}|GHed nX}h}g}x|D]} | d} y| d } Wnej od g} nX|i| obe | o@e | de i jo&x4| D]} || i | qLWq|| i | qe | oJe | de i jo0g|| ^ss)Failed to parse data returned from gmail.it(R RRRN(t splitlinestjointretsubtNonet SyntaxErrorRt Exceptionthas_keytlenttypettypestListTypeR( t pageContenttlinest_[1]Rtdatatinfotitemst itemsDicttnamesFoundTwicetitemtnamet parsedValue((Rs3/home/beckel/datasingularity.com/Texter/libgmail.pyt _parsePageQs@ F% '' cCsLg}x?|D]7}t|tjo|i|q |i|q W|S(sw Utility to help make it easy to iterate over each item separately, even if they were bunched on the page. (R ttupletextendR(t infoItemsRtgroup((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt _splitBunchesstSmartRedirectHandlercBseZdZdZRS(cCs ||_dS(N(t cookiejar(tselfR5((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt__init__scCsetid|id}|o|id|idntii||||||}|S(Nshttp[s]*://(.*?\.google\.com)tLocationtHosti(Rtmatcht getheadert add_headertgroupsturllib2tHTTPRedirectHandlerthttp_error_302(R6treqtfptcodetmsgtheaderstnew_hostR((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR@s  (R R R7R@(((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR4s t CookieJarcBs5eZdZdZddZdZdZRS(s A rough cookie handler, intended to only refer to one domain. Does no expiry or anything like that. (The only reason this is here is so I don't have to require the `ClientCookie` package.) cCs h|_dS(s N(t_cookies(R6((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR7scCsx|idD]}|idddgd \}}to d|GHn| p ||jo|idd|i|t build_openertConnectHTTPHandlertConnectHTTPSHandlerR4topenertstatet ValueErrort_cachedQuotaInfot_cachedLabelNames(R6R,tpwRRR((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR7s*         cCs7|io<tihtd6dd6dd6|id6|id6}n+tihtd6|id6|id 6}hd d 6d d 6}titd|d|}|i |}|ip{d}y@t i ||i d}ti |}|idd}Wntj otdnX|i |}ndS(s tcontinuetnulltattmailtservicetuserNametpasswordtEmailtPasswdswww.google.comR9s)Mozilla/5.0 (Compatible; libgmail-python)s User-AgentR&REsCheckCookie\?continue=([^"']+)is\x26t&s(Login failed. (Wrong username/password?)N(RRZR[RYR,RR>tRequestRt _retrievePageRtsearchR2tunquotetreplacetAttributeErrorRz(R6R&RERAtpageDatatRE_PAGE_REDIRECTtlinkt redirectURL((s3/home/beckel/datasingularity.com/Texter/libgmail.pytloginBs,      cCs|idjo dnt|tipti|}n|}|ii||iddy|ii|}Wnti j o}|GHdSX|i }|ii |i |S(s sCannot find urlopeners User-Agents)Mozilla/5.0 (Compatible; libgmail-python)N( RRReR>RRRXR<Rit HTTPErrorRjRRRE(R6t urlOrRequestRAtrespR'R((s3/home/beckel/datasingularity.com/Texter/libgmail.pyRks    c Cst|i|}y|t|_Wntj onXy4g}|tdD]}||tqR~|_Wntj onX|S(sL Retrieve & then parse the requested page content. i(R.RtD_QUOTARtKeyErrort D_CATEGORIEStCT_NAMER(R6RR(R%tcategory((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR.s4icKs;h|t6|t6tt6}|i||it|S(s (tU_SEARCHtU_STARTtU_THREADLIST_VIEWtU_VIEWtupdateR.R](R6t searchTypetstartR\Rp((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt_parseSearchResults    c Ksd}d}g}x|djp|ot||tjo|i|||}y|t} Wntj oPqXxB| D]:} t| dtij o | g} n|i| qW|t d}|t } || 7}qWt |||f|S(sW Only works for thread-based results at present. # TODO: Change this? i( RtTS_TOTALRtD_THREADRR R!R"RtD_THREADLIST_SUMMARYtTS_NUMtGmailSearchResult( R6RtallPagesR\Rttott threadsInfotthreadListSummaryR(tthreadstthtthreadsPerPage((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt_parseThreadSearchs(  cCs"|itdtddd|S(s7 Note: `version` seems to be ignored. tviewR,tjstver(RR]t U_PAGE_VIEW(R6tversion((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt_retrieveJavascriptscCs|i|d|S(s Folders contain conversation/message threads. `folderName` -- As set in Gmail interface. Returns a `GmailSearchResult` instance. *** TODO: Change all "getMessagesByX" to "getThreadsByX"? *** R(R(R6t folderNameR((s3/home/beckel/datasingularity.com/Texter/libgmail.pytgetMessagesByFolders cCs|itd|d|S(s: Returns a `GmailSearchResult` instance. tqR(RtU_QUERY_SEARCH(R6tqueryR((s3/home/beckel/datasingularity.com/Texter/libgmail.pytgetMessagesByQueryscCs2|i p|o|itn|idd S(s@ Return MB used, Total MB and percentage used. ii(RRtU_INBOX_SEARCH(R6trefresh((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt getQuotaInfoscCs*|i p|o|itn|iS(s (RRR(R6R((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt getLabelNamesscCs|itd|d|S(s tcatR(RtU_CATEGORY_SEARCH(R6tlabelR((s3/home/beckel/datasingularity.com/Texter/libgmail.pytgetMessagesByLabels cCs"t}|itd|d|S(s RR(tU_ORIGINAL_MESSAGE_VIEWRR](R6tmsgIdtPageView((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt getRawMessage scCs|itddtS(s Rsis:(RRtU_AS_SUBSET_UNREAD(R6((s3/home/beckel/datasingularity.com/Texter/libgmail.pytgetUnreadMessagess cCsO|itddt}y|tdt}Wntj o d}nX|S(s Rsis:i(RRRRt TS_TOTAL_MSGSR(R6R(R((s3/home/beckel/datasingularity.com/Texter/libgmail.pytgetUnreadMsgCounts   cCsKy|iit}Wn0tj o$|it|iit}nX|S(s (RRHtACTION_TOKEN_COOKIERRRn(R6R((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt_getActionToken(s  c Cs h ttg|t6dt6dt6dt6dt6|it6|i t 6|i t 6|i t6|id6|id6}|o|i|nt||i|i}h}d}xUt|iD]A\}} t| tp%| i||<| i||qqWd|_|i} | idd\} } | idd} | id d } x0|iD]"\} }| i|| |} qdWti t!d | }|i"| |i#|}d}|t%d }|t&ot'd |t(d|}nt)|t*|S(s `msg` -- `GmailComposedMessage` instance. `_extraParams` -- Dictionary containing additional parameters to put into POST message. (Not officially for external use, more to make feature additional a little easier to play with.) Note: Now returns `GmailMessageStub` instance with populated `id` (and `_account`) fields on success or None on failure. Rt1tsubjecttmsgbodys&&&&&&%s&&&&&&s it:s s R&itidt_accountN(+tU_SENDMAIL_VIEWtU_SAVEDRAFT_VIEWRtU_REFERENCED_MSGtU_THREADt U_DRAFT_MSGt U_COMPOSEIDRtU_ACTION_TOKENttot U_COMPOSE_TOtcct U_COMPOSE_CCtbcct U_COMPOSE_BCCRtbodyRRyRqRrRdRmReRRotepiloguet as_stringRMRRbR>RR]R<R.RtD_SENDMAIL_RESULTt SM_SUCCESStGmailMessageStubtSM_NEWTHREADIDR tSM_MSG(R6RDtasDraftt _extraParamsRpt mimeMessaget origPayloadst FMT_MARKERtitmtmsgStrtcontentTypeHeaderR&RVRWRAR(Rt resultInfo((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt sendMessage4sN              cCsOhtt6|it6|it6}|it|}|tdt djS(s ii( tU_DELETEMESSAGE_ACTIONtU_ACTIONRtU_ACTION_MESSAGERRR.R]tD_ACTION_RESULTt AR_SUCCESS(R6RDRpR(((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt trashMessages  cCs]htt6tt6|t6|it6|it6}|i t |}|t dt djS(s ii( t U_ALL_SEARCHRt U_UPDATE_VIEWRRRtU_ACTION_THREADRRR.R]R R (R6tactionIdtthreadRpR(((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt_doThreadActions cCs|it|}|S(s (RtU_MARKTRASH_ACTION(R6RR((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt trashThreadscCsOhtt6}h|t6|it6}tit|dti |}|S(s Helper method to create a Request instance for an update (view) action. Returns populated `Request` instance. R&( RRRRRR>RR]RZR[(R6RRpR&RA((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt_createUpdateRequests cCs=|it|}|i|}|GH|tdtdjS(s ii(RtU_CREATECATEGORY_ACTIONR.R R (R6t labelNameRAR(((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt createLabelscCs8|it|}|i|}|tdtdjS(s ii(RtU_DELETECATEGORY_ACTIONR.R R (R6RRAR(((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt deleteLabelscCsA|idt||f}|i|}|tdtdjS(s s%s%s^%sii(RtU_RENAMECATEGORY_ACTIONR.R R (R6t oldLabelNamet newLabelNameRAR(((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt renameLabels c Csd}d|df}|tii|}tddd|ddd|g}|i|d t}|o|o|i|n|S( s tFSV_01s%s %ss%sRRRRRqR(tostpathtbasenametGmailComposedMessageRRntaddLabel(R6RaRtFILE_STORE_VERSIONtFILE_STORE_SUBJECT_TEMPLATERRDtdraftMsg((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt storeFiles cCsg}tdddddd}|i|}|d}xh|D]`}t|djoG|dd jo6t|d |d |d |d }|i|qAqAWt|S(st Returns a GmailContactList object that has all the contacts in it as GmailContacts RtclRtcontactstpnltaiitceiiii(R]R.Rt GmailContactRtGmailContactList(R6t contactListtmyUrltmyDatat addressestentrytnewGmailContact((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt getContactss $%c Gst|djoQ||d}}t|djo|d}nd}td|||}ntdd}d"d |iid fd |ifd |ifd#g}|i}|djo|id|fnddddddddddg }|i } d} | hjox| i D]\} } | d7} d| } |i| | fd}t | dt o<|d7}d| || df}|i|| dfq0xd| D]\}|i |ddjo<|d7}d| ||df}|i||dfqqWq0Wnti|}ti|d|}|i|}|iddjoP|GH|iddjotdn!|idotd ntStSd!S($s Attempts to add a GmailContact to the gmail address book. Returns true if successful, false otherwise Please note that after version 0.1.3.3, addContact takes one argument of type GmailContact, the contact to add. The old signature of: addContact(name, email, notes='') is still supported, but deprecated. iiRiRtuptacttecRtGMAIL_ATtct_nmtct_emtct_idtctf_nRtptdR,teRtbtftttos ctsn_%02dsctsf_%02d_%02d_%sR&s"The contact was successfully addedsalready has the email addresss0Someone with same email already exists in Gmail.s,https://www.google.com/accounts/ServiceLoginsLogin has expired.N(sactR9(sct_idi(RR.R]RRHtgetNametgetEmailtgetNotesRt getMoreInfoR(ReRftcountRZR[R>RRtfindRtFalseRn(R6t myContactt extra_argsR,temailtnotestmyURLt myDataListt validinfokeystmoreInfotctsn_numtctsft ctsf_datat sectionenumtctsf_numtsubsectionenumR'R2RUR((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt addContact'sp           '  c Csitddd|d|ddd|iidd d }|i|}|id d jotStSd S(s Attempts to remove the contact that occupies id "id" from the gmail address book. Returns True if successful, False otherwise. This is a little dangerous since you don't really know who you're deleting. Really, this should return the name or something of the person we just killed. Don't call this method. You should be using removeContact instead. RR*R=tcR8tdcRR:RR7sThe contact has been deletediN(R]RRHRRKRLRn(R6RRQR((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt_removeContactByIds 7cCsf|i}|i|i}||jo|i|iSdGHdGHdG|GHdG|GHtSdS(st Attempts to remove the GmailContact passed in Returns True if successful, False otherwise. sUnable to delete.s@Has someone else been modifying the contacts list while we have?sOld version of person:sNew version of person:N(R6tgetContactByIdtgetIdR^RL(R6t gmailContacttnewContactListtnewVersionOfPersonToDelete((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt removeContacts    N("R R R RR7RRR.RRLRRRRRRRRRRRRR RRRRRRR(R6R[R^Rd(((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR~s<$ )   !    Z      ` R.cBsqeZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z RS( s7 Class for storing a Gmail Contacts list entry cGsd}d}t|djoB||}}|d}t|djo|d}qad}n||_||_||_||_h|_dS(s  Returns a new GmailContact object (you can then call addContact on this to commit it to the Gmail addressbook, for example) Consider calling setNotes() and setMoreInfo() to add extended information to this contact iRiiN(RRR,RORPRT(R6R,RORNRRP((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR7s        cCs d|i|i|i|ifS(Ns %s %s %s %s(RR,RORP(R6((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR}scCsvt|tptS|i|ijoH|i|ijo/|i|ijo|i|ijS(N(ReR.RLR`RFRGRH(R6tother((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt__eq__s cCs|iS(N(R(R6((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR`scCs|iS(N(R,(R6((s3/home/beckel/datasingularity.com/Texter/libgmail.pyRFscCs|iS(N(RO(R6((s3/home/beckel/datasingularity.com/Texter/libgmail.pyRGscCs|iS(N(RP(R6((s3/home/beckel/datasingularity.com/Texter/libgmail.pyRHscCs ||_dS(s Sets the notes field for this GmailContact Note that this does NOT change the note field on Gmail's end; only adding or removing contacts modifies them N(RP(R6RP((s3/home/beckel/datasingularity.com/Texter/libgmail.pytsetNotesscCs|iS(N(RT(R6((s3/home/beckel/datasingularity.com/Texter/libgmail.pyRIscCs ||_dS(s} moreInfo format --------------- Use special key values:: 'i' = IM 'p' = Phone 'd' = Company 'a' = ADR 'e' = Email 'm' = Mobile 'b' = Pager 'f' = Fax 't' = Title 'o' = Other Simple example:: moreInfo = {'Home': ( ('a','852 W Barry'), ('p', '1-773-244-1980'), ('i', 'aim:brianray34') ) } Complex example:: moreInfo = { 'Personal': (('e', 'Home Email'), ('f', 'Home Fax')), 'Work': (('d', 'Sample Company'), ('t', 'Job Title'), ('o', 'Department: Department1'), ('o', 'Department: Department2'), ('p', 'Work Phone'), ('m', 'Mobile Phone'), ('f', 'Work Fax'), ('b', 'Pager')) } N(RT(R6RT((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt setMoreInfos$cCsd}|d7}|d|i7}|ii}|i|ddi|d7}|d|i7}|d|i7}|d 7}|S( s9Returns a vCard 3.0 for this contact, as a strings BEGIN:VCARD s VERSION:3.0 s NOTE:%s sN:%sRJs sFN:%s sEMAIL;TYPE=INTERNET:%s s END:VCARD (RHRFRMtreverseRRG(R6tvcardtfullname((s3/home/beckel/datasingularity.com/Texter/libgmail.pytgetVCard)s   (R R R R7R}RfR`RFRGRHRgRIRhRl(((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR.s         %R/cBsqeZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z RS( st Class for storing an entire Gmail contacts list and retrieving contacts by Id, Email address, and name cCs ||_dS(N(R0(R6R0((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR7CscCs1dig}|iD]}|t|q~S(Ns (RR0Rf(R6R%R+((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR}EscCs t|iS(s, Returns number of contacts (RR0(R6((s3/home/beckel/datasingularity.com/Texter/libgmail.pytgetCountGscCs|iS(sC Returns an array of all the GmailContacts (R0(R6((s3/home/beckel/datasingularity.com/Texter/libgmail.pytgetAllContactsLscCs3|i|}t|djo |dStSdS(s Gets the first contact in the address book whose name is 'name'. Returns False if no contact could be found iN(tgetContactListByNameRRL(R6R,tnameList((s3/home/beckel/datasingularity.com/Texter/libgmail.pytgetContactByNameRs cCs3|i|}t|djo |dStSdS(s Gets the first contact in the address book whose name is 'email'. As of this writing, Gmail insists upon a unique email; i.e. two contacts cannot share an email address. Returns False if no contact could be found iN(tgetContactListByEmailRRL(R6ROt emailList((s3/home/beckel/datasingularity.com/Texter/libgmail.pytgetContactByEmail_s  cCs3|i|}t|djo |dStSdS(s Gets the first contact in the address book whose id is 'myId'. REMEMBER: ID IS A STRING Returns False if no contact could be found iN(tgetContactListByIdRRL(R6tmyIdtidList((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR_os  cCsBg}x5|iD]*}|i|jo|i|qqW|S(s This function returns a LIST of GmailContacts whose name is 'name'. Returns an empty list if no contacts were found (R0RFR(R6R,RpR4((s3/home/beckel/datasingularity.com/Texter/libgmail.pyRo~s  cCsBg}x5|iD]*}|i|jo|i|qqW|S(sN This function returns a LIST of GmailContacts whose email is 'email'. As of this writing, two contacts cannot share an email address, so this should only return just one item. But it doesn't hurt to be prepared? Returns an empty list if no contacts were found (R0RGR(R6RORsR4((s3/home/beckel/datasingularity.com/Texter/libgmail.pyRrs  cCsBg}x5|iD]*}|i|jo|i|qqW|S(s This function returns a LIST of GmailContacts whose id is 'myId'. We expect there only to be one, but just in case! Remember: ID IS A STRING Returns an empty list if no contacts were found (R0R`R(R6RvRwR4((s3/home/beckel/datasingularity.com/Texter/libgmail.pyRus  cCspg}xc|iD]X}ti|ti}|i|ip|i|io|i|qqW|S(s This function returns a LIST of GmailContacts whose name or email address matches the 'searchTerm'. Returns an empty list if no matches were found. (R0Rtcompilet IGNORECASERRFRGR(R6t searchTermt searchResultsR4R?((s3/home/beckel/datasingularity.com/Texter/libgmail.pyRs  ,(R R R R7R}RmRnRqRtR_RoRrRuR(((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR/>s         RcBs2eZdZdZdZdZdZRS(s c Csy+t|dtij o |g}nWntj o dGHnX||_||_g|_x+|D]#}|iit||dqhWdS(sI `threadsInfo` -- As returned from Gmail but unbunched. isNo messages foundN( R R!R"t IndexErrorRRt_threadsRt GmailThread(R6taccountRRR((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR7s    cCs t|iS(s (titerR}(R6((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt__iter__scCs t|iS(s (RR}(R6((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt__len__scCs|ii|S(s (R}t __getitem__(R6tkey((s3/home/beckel/datasingularity.com/Texter/libgmail.pyRs(R R R R7RRR(((s3/home/beckel/datasingularity.com/Texter/libgmail.pyRs    tGmailSessionStatecBs&eZdZdddZdZRS(s RcCsS|o|i|if|_n0|ott|d|_n tddS(s R^sSGmailSessionState must be instantiated with either GmailAccount object or filename.N(R,RRRRiR(R6RRa((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR7s cCs t|it|dddS(s twbiN(RRRi(R6Ra((s3/home/beckel/datasingularity.com/Texter/libgmail.pytsavesN(R R R RR7R(((s3/home/beckel/datasingularity.com/Texter/libgmail.pyRs t_LabelHandlerMixincBs;eZdZdZdZdZdZdZRS(sv Note: Because a message id can be used as a thread id this works for messages as well as threads. cCs d|_dS(N(Rt_labels(R6((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR7scCs ||_dS(N(R(R6t labelList((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt_makeLabelListscCsH|iit||}|ip|ign|ii||S(s (RRtU_ADDCATEGORY_ACTIONRRR(R6RR((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR$s   cCsN|iit||}t}y|ii|Wn t}nX|o|S(s (RRtU_REMOVECATEGORY_ACTIONRnRtremoveRL(R6RRt removeLabel((s3/home/beckel/datasingularity.com/Texter/libgmail.pyRs cCs|iS(N(R(R6((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt getLabels(s(R R R R7RR$RR(((s3/home/beckel/datasingularity.com/Texter/libgmail.pyRs    R~cBsDeZdZdZdZdZdZdZdZRS(s  Note: As far as I can tell, the "canonical" thread id is always the same as the id of the last message in the thread. But it appears that the id of any message in the thread can be used to retrieve the thread information. cCsti|||_|ii|_|t|_|t|_|t|_ |t |_ ||_ y+t tid|i id|_Wntj o}d|_nXg|_|i|tdS(s s \((\d+?)\)\ZiN(RR7t_parentRt T_THREADIDRtT_SUBJECT_HTMLRtT_SNIPPET_HTMLtsnippettT_AUTHORS_HTMLt_authorsR'tintRRR2t_lengthRt _messagesRt T_CATEGORIES(R6tparentRR'((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR76s         cCsh td6td6td6td6td6td6td6td6td 6t d 6t d 6}||jo|i ||St d |d S(sJ Dynamically dispatch some interesting thread properties. tunreadtstartdatetauthorstflagsRRt categoriesRctmatching_msgidt extra_snippetsno attribute %sN( tT_UNREADtT_STARt T_DATE_HTMLRtT_FLAGSRRRt T_ATTACH_HTMLtT_MATCHING_MSGIDtT_EXTRA_SNIPPETR'R(R6R,tattrs((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt __getattr__Zs   cCs|iS(s (R(R6((s3/home/beckel/datasingularity.com/Texter/libgmail.pyRnscCs-|ip|i||_nt|iS(s (Rt _getMessagesR(R6((s3/home/beckel/datasingularity.com/Texter/libgmail.pyRts cCsV|ip|i||_ny|ii|}Wntj o g}nX|S(s (RRRR|(R6RR((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR|s  c Cs|iitdtd|idd}g}xttfttfgD]\}}y||}Wnt j o qFqFXt |dt i jo |g}nx*|D]"}|t ||d|g7}qWqFW|S(s RRRs in:anywhereitisDraft(RRRtU_CONVERSATION_VIEWRt D_MSGINFORLt D_DRAFTINFORnRR R!R"t GmailMessage(R6RR(RRRtmsgsInfoRD((s3/home/beckel/datasingularity.com/Texter/libgmail.pyRs"    $( R R R R7RRRRR(((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR~-s $    RcBseZdZdddZRS(sp Intended to be used where not all message information is known/required. NOTE: This may go away. cCs#ti|||_||_dS(s N(RR7RR(R6RR((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR7s  N(R R R RR7(((s3/home/beckel/datasingularity.com/Texter/libgmail.pyRsRcBs5eZdZedZdZeeddZRS(s cCs||_|ii|_|t|_|t|_|t|_|t|_ |t |_ |t |_ |t|_|t|_g}|tD]}|t||q~|_||_d|_dS(sO Note: `msgData` can be from either D_MSGINFO or D_DRAFTINFO. N(RRtMI_AUTHORFIRSTNAMEtauthortMI_MSGIDRtMI_NUMtnumbert MI_SUBJECTRtMI_TORtMI_CCRtMI_BCCRtMI_AUTHOREMAILtsendert MI_ATTACHINFOtGmailAttachmentt attachmentsRRt_source(R6RtmsgDataRR%tattachmentInfo((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR7s         * cCs-|ip|ii|i|_n|iS(s (RRRR(R6((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt _getSources tdocR(R R R RLR7Rtpropertytsource(((s3/home/beckel/datasingularity.com/Texter/libgmail.pyRs  RcBsMeZdZdZdZeeddZdZeeddZRS(s cCsY||_|ii|_|t|_|t|_|t|_|t|_ d|_ dS(s N( RRtA_IDRt A_FILENAMERat A_MIMETYPEtmimetypet A_FILESIZEtfilesizeRt_content(R6RR((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR7s     c CsQ|ip@|iitdtddd|id|iii|_n|iS(s RtdisptattdtattidR(RRRR]tU_ATTACHMENT_VIEWRR(R6((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt _getContents   %RRcCs#d|iii|ii|ifS(s Returns the "full path"/"full id" of the attachment. (Used to refer to the file when forwarding.) The id is of the form: "__" s%s_%s_%s(RR(R6((s3/home/beckel/datasingularity.com/Texter/libgmail.pyt _getFullId s  ( R R R R7RRtcontentRt_fullId(((s3/home/beckel/datasingularity.com/Texter/libgmail.pyRs    R#cBs#eZdZdddddZRS(s cCsC||_||_||_||_||_||_||_dS(s `filenames` - list of the file paths of the files to attach. `files` - list of objects implementing sub-set of `email.Message.Message` interface (`get_filename`, `get_content_type`, `get_payload`). This is to allow use of payloads from Message instances. TODO: Change this to be simpler class we define ourselves? N(RRRRRRqRr(R6RRRRRRqRr((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR7s      N(R R R RR7(((s3/home/beckel/datasingularity.com/Texter/libgmail.pyR#st__main__(tgetpassisGmail account name: s Password: s!Domain? [leave blank for Gmail]: Rs Please wait, logging in...s Login failed. (%s)sLogin successful. s%s of %s used. (%s) s0Select folder or label to list: (Ctrl-C to exit)s %d. %ssChoice: sNo threads found in `%s`.s%s messages in threads snumber of threads:snumber of messages:s Done.(htVersionRNt lgconstantsR tpprintRRZR>RgR!tcPickleRRtemail.MIMEBaseRtemail.MIMETextRtemail.MIMEMultipartRRRRRRtU_STARRED_SEARCHR tU_DRAFTS_SEARCHt U_SENT_SEARCHt U_SPAM_SEARCHtSTANDARD_FOLDERSRRtDI_BODYRLt versionWarnedRxtDOTALLtRE_SPLIT_PAGE_CONTENTRRR R.R3R?R4RGR]RyRzR~R.R/RRtobjectRR~RRRR#R tsysRtargvR,R|t raw_inputRRtgaRRAR{Rt quotaInfot QU_SPACEUSEDt quotaMbUsedtQU_QUOTAt quotaMbTotalt QU_PERCENTt quotaPercentRtsearchesRdtoptionIdt optionNameRRR'RRnRRRRRRRRRDRRtKeyboardInterrupt(((s3/home/beckel/datasingularity.com/Texter/libgmail.pyts        0 0  4v(1v12            !