MpjzddlmZ gdZddlZddlZddlZddlZddlZddlZ ddl Z ddl Z ddl Z ddl Z ddlZddlZddlZddlZddlZddlZddlZddlZddlZddlZddlZddlZddlZddlmZddlmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*ddl+m,Z,ddl-m.Z.dd l/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6e)r dd l7m8Z8dd l9m:Z:ejve<Z=e=j}ej~ejd d e(dZAd;dZBd;dZCddZGd?dZHd@dZIdAdZJdBdZKdCdZLdDdZMdEdZNdFdZOdGdZPdHdZQdIdZRdJd ZSdKd!ZTdLd"ZUdMd#ZVdNd$ZWdOd%ZXdPd&ZYdQd'ZZdRd(Z[dSd)Z\dTd*Z]dJd+Z^dJd,Z_dejdd-d.f dUd/ZadVd0ZbdWd1ZcdWd2ZddWd3ZedXd4ZfdYd5ZgdZd6Zhd[d7Zid\d8Zjd]d9Zkd^d:Zly)_) annotations)& addNumToDiraddNumToZipDir bitwiseAdjustbitwiseAdjustedAnd bytesToGuidceilDiv cloneOleFile createZipOpen decodeRfc2047dictGetCasedKeydividefiletimeToDatetime filetimeToUtcfindWk fromTimeStampgetCommandArgs guessEncoding htmlSanitize inputToBytesinputToMsgPath inputToStringisEncapsulatedRtf makeWeakRefmsgPathToString parseTypeprepareFilenameroundUprtfSanitizeHtmlrtfSanitizePlain setupLoggingstripRtftryGetMimetypeunsignedToSignedInt unwrapMsgunwrapMultipart validateHtmlverifyPropertyId verifyTypeN)escape) AnyAnyStrCallableDictIterableListOptionalSequence SupportsBytesTypeVar TYPE_CHECKINGUnion) constants)AttachmentType)ConversionErrorDependencyErrorExecutableNotFoundIncompatibleOptionsErrorInvalidPropertyIdErrorTZErrorUnknownTypeError)MSGFile)AttachmentBase DEVELOPER_TctddD]=} |j|jd|dz}tj||cSy#t $r }Yd}~Od}~wwxYw)@ Attempt to create the directory with a '(n)' appended. d ()N)range with_namenameosmakedirs Exception)dirNamei newDirNamees _/mnt/ssd/data/Dropbox/adrian/scripts/msg_venv/lib/python3.12/site-packages/extract_msg/utils.pyrrgsk1c]  **7<z!addNumToZipDir..|sF1<< ,FsN)rLrMrNstrrstripanynamelist)rR_ziprSrTr^s @rVrruss1c]&&w||1#Qi'?@ *o,,S1C7 FdmmoFF   ch|dkr td|t|dddjdz S)a| Uses a given mask to adjust the location of bits after an operation like bitwise AND. This is useful for things like flags where you are trying to get a small portion of a larger number. Say for example, you had the number ``0xED`` (``0b11101101``) and you needed the adjusted result of the AND operation with ``0x70`` (``0b01110000``). The result of the AND operation (``0b01100000``) and the mask used to get it (``0x70``) are given to this function and the adjustment will be done automatically. :param mask: MUST be greater than 0. :raises ValueError: The mask is not greater than 0. r7Mask MUST be greater than 0N1 ValueErrorbinindexinpmasks rVrrs9  ax677 #d)DbD/'', ,,recn|dkr td||zt|dddjdz S)z Preforms the bitwise AND operation between :param inp: and :param mask: and adjusts the results based on the rules of :func:`bitwiseAdjust`. :raises ValueError: The mask is not greater than 0. r7rgNrhrirjrns rVrrs= ax677 $J3t9TrT?005 55rec tjjj|}d|ddd|ddd|ddd|dd dj j d|ddd j j d S) z. Converts a bytes instance to a GUID. {r08X-r704XrHN})r8stST_GUIDunpackhexupper) bytesInputguidValss rVrrs||##**:6H  C (1+c!2!HQK3DAhqkRTSToFYFYF[FaFaFcEddefnopfqrsrtfufyfyf{gBgBgDfEEG HHrec|| z S)z Returns the ``int`` from the ceiling division of n / d. ONLY use ``int``\s as inputs to this function. For ``int``\s, this is faster and more accurate for numbers outside the precision range of ``float``. )nds rVr r s1"W:recddlm}tj|5}|}|j |dddj |y#1swYxYw)z Uses the ``OleWriter`` class to clone the specified OLE file into a new location. Mainly designed for testing. r7) OleWriterN) ole_writerrolefile OleFileIO fromOleFilewrite) sourcePath outputPathrfwriters rVr r sO&   : &!1 LL s AAcdfd }|S)z Creates a wrapper for the open function of a ZipFile that will automatically set the current date as the modified time to the current time. c|dk(rCtj|tjjj dd}||g|i|S)Nw)zipfileZipInfodatetimenow timetuple)rNmodeargskwargsfuncs rV_openzcreateZipOpen.._opensP 3;??4):):)>)>)@)J)J)LRa)PQDD$0000re)rr)rrs` rVr r s 1 Lrec|jdd}djdtjj |DS)zF Decodes text encoded using the method specified in RFC 2047.  c3K|]7}t|dtr|dj|dxsdn|d9yw)rr7zraw-unicode-escapeN) isinstancebytesdecoder\r]s rVr_z decodeRfc2047..sI 6@!e5L! AaD001RSTURVVs=?)replacejoinemailheader decode_header)encodeds rVr r sC oofb)G 77++G4 recz tfd|jDS#t$r twxYw)z` Retrieves the key from the dictionary with the proper casing using a caseless key. c3fK|](}|jjk(s%|*ywrZ)lower)r\r]keys rVr_z"dictGetCasedKey..s$I1 SYY[0HQIs&11)nextkeys StopIterationKeyError)_dictrs `rVr r s8 I IJJ sms!%:c|ttt||Dcgc]}|||z||dzzc}Scc}w)ar Divides a string into multiple substrings of equal length. If there is not enough for the last substring to be equal, it will simply use the rest of the string. Can also be used for things like lists and tuples. :param string: The string to be divided. :param length: The length of each division. :returns: list containing the divided strings. Example: .. code-block:: python >>> a = divide('Hello World!', 2) >>> print(a) ['He', 'll', 'o ', 'Wo', 'rl', 'd!'] >>> a = divide('Hello World!', 5) >>> print(a) ['Hello', ' Worl', 'd!'] r7)rLr len)stringlengthr]s rVrrs=.:?ws6{TZ?[9\ ]AF6A:fA. / ]] ]s9c  |dkrtjj|S|dk(rddlm}|ddddd }||_|S|d k(rt j S|d kDr=ddlm}|d ddd} |tjt| z }||_|St't|S#t$rc|j}||j|j|j|j|j |j"|j$}YwxYw#t($rt*$rt-dt|d|dwxYw)av Converts a filetime into a ``datetime``. Some values have specialized meanings, listed below: * ``915151392000000000``: December 31, 4500, representing a null time. Returns an instance of extract_msg.null_date.NullDate. * ``915046235400000000``: 23:59 on August 31, 4500, representing a null time. Returns extract_msg.constants.NULL_DATE. }*{G l@G^er7)NullDatei ;lR&lelbnei)secondszTimestamp value of z (raw: z^) caused an exception. This was probably caused by the time stamp being too far in the future.)rfiletime2datetime null_daterfiletimer8 NULL_DATEr timedeltar OverflowErrormaxyearmonthdayhourminutesecond microsecondrr?rQrk)rawTimerdatems rVrr sb&w ' '??44W= = * * ,D"b"b1D#DMK * *&& & ) ) +D!Q*D c**]75KLL$DMK w!78 8! cHH!((TUTaTab  c  w.}W/E.FggYWuvw wwsG#D D D D 2"B1D D 1A)DD DD .Ec|dz dz S)z4 Converts a FILETIME into a unix timestamp. rgcArros rVrr@s $ $ 22rec|r[tjj|r1tj|tjr|St dt dt jd}|r|St d)z Attempt to find the path of the wkhtmltopdf executable. :param path: If provided, the function will verify that it is executable and returns the path if it is. :raises ExecutableNotFound: A valid executable could not be found. zAPath provided was not a valid executable (execution bit not set).z6Path provided was not a valid executable (not a file). wkhtmltopdfzCould not find wkhtmltopdf.)rOpathisfileaccessX_OKr<shutilwhich)r candidates rVrrGsi 77>>$ yyrww' ()lmm$%]^ ^ ]+I : ;;rec tj}tjj ||S#t$r tdwxYw)zS Returns a ``datetime`` from the UTC timestamp given the current timezone. zzError occured using tzlocal. If you are seeing this, this is likely a problem with your installation ot tzlocal or tzdata.)tzlocal get_localzonerQr?r fromtimestamp)stamptzs rVrras[U  " " $    * *5" 55 USU U Us 6A c tjtjd}|j }|j }|j d}|j ddddd |j d d dd |j dddd |j dddddd|j ddd|j ddd|j dd d!|j d"d#dd$ |j d%d&dd' |j d(d)dd* |j d+d,dd- |j d.d/d0|j d1d2d3d45|j d6d7dd8 |j d9d:d;d<=|j d>d?dd@ |j dAdBddC |j dDdEddF |j dGdHddI |j dJdKdL|j dMdNddO |j dPdQddR |j dSdTddU |j dVdWddX |j dYdZdd[ |j d\d]dd^ |j d_d`dda |j dbdcdddde |j dfdgdh|j didjdkddl |j dmdnddo |j dpdqddr |j dsdtduddv |j dwdxd3gdyz|j |}|jrA|jjtjjj|jr|jr td{|j r|j"xsd||_|j$rg}|j$D]}|j'd}r d~|ddz}n|j'drd|d|dz}|j)d}t+|d|k(r|j|g|j|d|jdj-|d|d||_|j.r*d|_d|_d|_d|_d|_d|_|j<ry|jr td|jr tdg} |jD]} | t=j<| z } t+| dk(r t?d| |_|jr#t+|jd|kDr td|j"dk(rt@jB|_"nQ|j"d|k(rt@jF|_"n,|j"dk(rt@jH|_"nd|_"|jr|jJs t?d|S)ag Parse command-line arguments. :raises IncompatibleOptionsError: Some options were provided that are incompatible. :raises ValueError: Something about the options was invalid. This could mean an option was specified that requires another option or it could mean that an option was looking for data that was not found. extract_msg) descriptionprogT)requiredz--use-content-idz--cidcid store_truez_Save attachments by their Content ID, if they have one. Useful when working with the HTML body.)destactionhelpz--jsonjsonz&Changes to write output files as json.z--file-logging fileLoggingz0Enables file logging. Implies --verbose level 1.z-vz --verboseverbosecountrzFTurns on console logging. Specify more than once for higher verbosity.)rrdefaultrz--loglogz&Set the path to write the file log to.)rrz--config configPathz-Set the path to load the logging config from.z--outoutPathzJSet the folder to use for the program output. (Default: Current directory)z--use-filename useFilenamezBSets whether the name of each output is based on the MSG filename.z --dump-stdout dumpStdoutz^Tells the program to dump the message body (plain text) to stdout. Overrides saving arguments.z--htmlhtmlzLSets whether the output should be HTML. If this is not possible, will error.z--pdfpdfz=Saves the body as a PDF. If this is not possible, will error.z --wk-pathwkPathz+Overrides the path for finding wkhtmltopdf.z --wk-options wkOptions*zSets additional options to be used in wkhtmltopdf. Should be a series of options and values, replacing the - or -- in the beginning with + or ++, respectively. For example: --wk-options "+O Landscape")rnargsrz--prepared-html preparedHtmlzoWhen used in conjunction with --html, sets whether the HTML output should be prepared for embedded attachments.z --charsetcharsetutf-8zMCharacter set to use for the prepared HTML in the added tag. (Default: utf-8))rrrz--rawrawzKSets whether the output should be raw. If this is not possible, will error.z--rtfrtfzKSets whether the output should be RTF. If this is not possible, will error.z--allow-fallback allowFallbackz[Tells the program to fallback to a different save type if the selected one is not possible.z--skip-body-not-foundskipBodyNotFoundzQSkips saving the body if the body cannot be found, rather than throwing an error.z--zipzipz%Path to use for saving to a zip file.z --save-header saveHeaderz$Store the header in a separate file.z--attachments-onlyattachmentsOnlyz2Specify to only save attachments from an MSG file.z --skip-hidden skipHiddenzJSkips any attachment marked as hidden (usually ones embedded in the body).z --no-folders noFolderszvStores everything in the location specified by --out. Requires --attachments-only and is incompatible with --out-name.z--skip-embedded skipEmbeddedz5Skips all embedded MSG files when saving attachments.z--extract-embeddedextractEmbeddedzUExtracts the embedded MSG files as MSG files instead of running their save functions.z--overwrite-existingoverwriteExistingzDisables filename conflict resolution code for attachments when saving a file, causing files to be overwriten if two attachments with the same filename are on an MSG file.z--skip-not-implementedz --skip-niskipNotImplementedz[Skips any attachments that are not implemented, allowing saving of the rest of the message.z --out-nameoutNamezaName to be used with saving the file output. Cannot be used if you are saving more than one file.z--globz --wildcardglobzFInterpret all paths as having wildcards. Incompatible with --out-name.z--ignore-rtfdeignoreRtfDeErrorsz}Ignores all errors thrown from RTFDE when trying to save. Useful for allowing fallback to continue when an exception happens.z --progressprogresszIShows what file the program is currently working on during it's progress.z-sz--stdinstdinz:Read file from stdin (only works with one file at a time).msgsmsgzAn MSG file to be parsed.)metavarrrrz/--out-name is not compatible with --no-folders.r7z++z--rHN+ru Fz1--out-name is not supported when using wildcards.z.--stdin is not supported with using wildcards.z;Could not find any MSG files using the specified wildcards.z;--out-name is not supported when saving multiple MSG files.rCz4--no-folders requires the --attachments-only option.)&argparseArgumentParserr8MAINDOCadd_mutually_exclusive_group add_argument parse_argsrrappendsysbufferreadr rr=rrrr[splitrrrrrrrrrrrkloggingERRORlogLevelWARNINGINFOr) rparser outFormat inputFormat inputTypeoptionsroptionr! fileListsrs rVrros $ $93D3D] [F335I557K33t3DI *G% ~@8&EG (}\OQ k 'STeg eEG  LN iik (}\ac l<}8&km7| _a  (JL [hi )|OP  )Wln7| mo7| mo *z| /6HQ]pr eDF l<CE/6GP\ TV l<ik [VW )|TV ,3D\tv .5HQ]KL 0+DXamz|\ ABX|&eg (/B<]^  :lik4Y[65R8:%G}} CII,,11347,,&'XYY!//.Q '' 6F  &qr *""3'vabz)LL%E5zQ  (  q*  %)!45 6 &    # || ??*+^_ _ ==*+[\ \ LL )D 4 (I ) y>Q Z[ [  3w||,q0&'dee!"== A "?? A "<<!8!8OPP Nrec ddl}d}d|jdddDD]Z}|j j dry |j j d sD||j |d zz }\ |r|j|x}d d kry|dS#t$r tdwxYw#t$r}td|d}~wwxYw)a Analyzes the strings on an MSG file and attempts to form a consensus about the encoding based on the top-level strings. Returns ``None`` if no consensus could be formed. :raises DependencyError: ``chardet`` is not installed or could not be used properly. rNzECannot guess the encoding of an MSG file if chardet is not installed.rec3DK|]}t|dk(s|dyw)r7rNrrs rVr_z guessEncoding..AsN!#a&A+1Ns  TF001f utf-16-le001e confidenceg?encodingzFailed to detect encoding: ) chardet ImportErrorr;listDirrendswith getStreamdetectrQ)rr7datarNresultrUs rVrr2sg DNs{{4>N0 ::<  ( ZZ\ " "6 * CMM$'%/ /D 0A'.."66 EKj!! geffg A ;A3?@@As)B!B9B9!B69 CCCct|}|jddjdd}tjjj d|}|S)z Santizes the input for injection into an HTML string. Converts charactersinto forms that will not be misinterpreted, if necessary. r z
c<dt|jdzS)Nz r)rgroup)spacess rVzhtmlSanitize.._s(SVWEY:Yre) htmlEscaperr8reHTML_SAN_SPACEsubrs rVrrQsQ S/C ++fd # + +D' :C ,, % % ) )+Y[^ _C Jrect|tr|St|tr|j|S|yt |dr t|St d)a0 Converts the input into bytes. :raises ConversionError: The input cannot be converted. :raises UnicodeEncodeError: The input was a str but the encoding was not valid. :raises TypeError: The input has a __bytes__ method, but it failed. :raises ValueError: Same as above. re __bytes__zCannot convert to bytes.)rrr`encodehasattrr:)objr6s rVrrdsT#u #szz(## {sK Sz 4 55rec8t|ttfrdj|}t |d}d|vsd|vr t d|j ddjdDcgc]}|s| }}td|Dr t d|Scc}w) zo Converts the input into an msg path. :raises ValueError: The path contains an illegal character. rXr:!z1Illegal character ("!" or ":") found in MSG path.\c38K|]}t|dkDyw)rNr0rs rVr_z!inputToMsgPath..s $13q6B; $sz5Path segments must not be greater than 31 characters.) rlisttuplerrrkrr!rb)ror]rets rVrrzs #e}%hhsm W %C  czSCZLMMkk$,2237 =11 =C = $ $$PQQ J >s *B2Bct|tr|St|tr|j|S|yt d)zh Converts the input into a string. :raises ConversionError: The input cannot be converted. rzCannot convert to str type.)rr`rrr:) bytesInputVarr6s rVrrsD -% M5 )##H--  ;<>recht|tsdj|}|jddS)z` Converts an MSG path (one of the internal paths inside an MSG file) into a string. rXrQ)rr`rrrs rVrrs, c3 hhsm ;;tS !!rec  }t|}|dk(r |S|dk(r|dk7rtjdy|dk(r/tjj j |dddS|dk(r/tjjj |dddS|dk(r/tjjj |dddS|d k(r,tjjj |dS|d k(rBtjtjjj |dd z S|d k(rStjjj |d}tjtj| zS|dk(rBddlm}m}tjjj |ddd} ||}|S|dk(r2tjj j |ddddk7S|dk(r t)d|dk(r,tjj*j |dS|dk(r|j-|S|dk(r|j-dS|dk(r7tjj*j |d}t/|S|dk(r t1|S|dk(rOtjj j |ddd} |ddk(rddlm} | |S| |d| dzfS|dk(r t)d |d!k(r t)d"|d#k(r|S|d$zd$k(r|d%vr|D cgc]} | j-|dd&} } t7j d't| d(} t| }||kDr&tjd)|d*|dk7rd+nd,d-|d.t9|D]?\} }| | t|k7stjd/| | d-t|d.A| S|d0k(rt;j<|} t?fd1tAtd2zD} t| }||kDr&tjd)|d*|dk7rd+nd,d-|d.t9|D]?\} }| | t|k7stjd/| | d-t|d.A| S|d3vrt|k7r/tjd)d4dk(rd5nd6d-t|d.|d7k(rt?d8|DS|d9k(rt?d:|DS|d;k(rt?d<|DS|d=k(rt?d>|DS|d?k(rd@|D}t?dA|DS|dBk(rt?dC|DS|dDk(rt?dE|DS|dFk(rt?dG|DS|St)dH|dI|dJ|S#t&$rNtjd|d tjd||dY|S#t&$rYY|SwxYwwxYwcc} w)Ka! Converts the data in :param stream: to a much more accurate type, specified by :param _type:. :param _type: The data's type. :param stream: The data to be converted. :param encoding: The encoding to be used for regular strings. :param extras: Used in the case of types like PtypMultipleString. For that example, extras should be a list of the bytes from rest of the streams. :raises NotImplementedError: The type has no current support. Most of these types have no documentation in [MS-OXMSG]. rr7sz1Property type is PtypNull, but is not equal to 0.NrHrwrCri'days ) ErrorCode ErrorCodeTypezEError type found that was not from Additional Error Codes. Value was z+. You should report this to the developers.z$REPORT TO DEVELOPERS: Error type of z was found. zmCurrent version of extract-msg does not support the parsing of PtypObject/PtypEmbeddedTable in this function.rr2@H)ServerIDzParsing for type 0x00FD (PtypRestriction) has not yet been implmented. If you need this type, please create a new issue labeled "NotImplementedError: parseType 0x00FD PtypRestriction".zParsing for type 0x00FE (PtypRuleAction) has not yet been implmented. If you need this type, please create a new issue labeled "NotImplementedError: parseType 0x00FE PtypRuleAction".ii)iirhyw)rdrNr8ry ST_LE_UI32r{)r\posstreams rVr_zparseType..Bs@xY\ILL33::6#a%Aa;PQRSTxsAArx)@Hz entryiesr}c3tK|]0}tjjj|d2ywrN)r8ry ST_LE_UI16r{rs rVr_zparseType..N*RaY\\44;;A>qAR68r~c3tK|]0}tjjj|d2ywrryrs rVr_zparseType..Prrrc3tK|]0}tjjj|d2ywr)r8ry ST_LE_F32r{rs rVr_zparseType..R*QQY\\33::1=a@Qrrc3tK|]0}tjjj|d2ywrr8ry ST_LE_F64r{rs rVr_zparseType..Trrrc3tK|]0}tjjj|d2ywrrrs rVr_zparseType..Vs*N!),,0077:1=Nrc3jK|]+}tjtj|z-yw)rfN)r8PYTPFLOATINGTIME_STARTrr)r\amounts rVr_zparseType..Ws(wflY==@R@RZ`@aaws13rc3tK|]0}tjjj|d2ywr)r8ry ST_LE_UI64r{rs rVr_zparseType..Yrrrc3K|]9}ttjjj |d;ywr)rr8ryrr{rs rVr_zparseType..[s0aUV]9<<+B+B+I+I!+LQ+OPas?Arc32K|]}t|ywrZ)rrs rVr_zparseType..]s<[^|Nr)r\rSs rVr_z"prepareFilename..isI!3H*H1Is )rstrip)filenames rVrrcs" 77IhI I O O QQrec|||z |zzS)zH Rounds :param inp: up to the nearest multiple of :param mult:. r)romults rVrrls $*$ $$rec |syd}|D]}dt|cxkrdkr(nn%|dk(r|dz }%|dk(r|dz }0|dvr|d z }||z }?t|dksdt|cxkrd krnn|d t|d z }w|jd }|djdtjdt |dzd|Dz }|S)zF Sanitizes input to an RTF stream that has encapsulated HTML. r ruz'{\*\htmltag84 <}\htmlrtf <\htmlrtf0 >z&{\*\htmltag84 >}\htmlrtf >\htmlrtf0rQrsrxrQ\'02Xr2c3(K|] }d|d ywz\u?Nrrs rVr_z"rtfSanitizeHtml..[QA3aj[rHhordrKrrr{rrooutputcharencs rVrrss  F\ T S s{DDCC++dNF$ Y^sc$i636 CIc?+ +F++k*C bgg[&--!CHPQM?RS@TVY2Z[[ [F)\, Mrec z|syd}|D]}dt|cxkrdkrnn|dvr|dz }||z })t|dksdt|cxkrdkrnn|dt|dz }a|jd }|djd tjd t |d zd |Dz }|S)z0 Sanitizes input to a plain RTF stream. rrrrrQrrrr2c3(K|] }d|d ywrrrs rVr_z#rtfSanitizePlain..rrrurHrrrs rVr r s  F \ T S ''$ dNF Y^sc$i636 CIc?+ +F++k*C bgg[&--!CHPQM?RS@TVY2Z[[ [F \ MreFEXTRACT_MSG_LOG_CFGctjtjdz dz }tj dk(rd}|dz}ntj dk(rd}|dz}|rtj|n|}|tjd tjd tjd |g}d }|D]} | j s| }nt j|d } | rStjj | r4tjj| rtj| }|sktd tdtt|dd tj|tjdtj dyt|d5} t!j"| } d d d  dD]} d| d| vs|rtjj%tjj'|r|n | d| dx| d| d<}tj|j}|j rt j(|| d| d< tj*j-| tj0j3|y#1swYxYw#t.$r }tdt|Yd }~Ud }~wwxYw)a Setup logging configuration :param defaultPath: Default path to use for the logging configuration file. :param defaultLevel: Default logging level. :param env_key: Environment variable name to search for, for setting logfile path. :param enableFileLogging: Whether to use a file to log or not. :returns: ``True`` if the configuration file was found and applied, ``False`` otherwise r=zlogging-configntNULzlogging-nt.jsonposixz /dev/nullzlogging-posix.jsonz logging.jsonz../logging.jsonz../../logging.jsonNz.Unable to find logging.json configuration filezMake sure a valid logging configuration file is referenced in the defaultPath argument, is inside the extract_msg install location, or is available at one of the following file-paths:r7)levelzThe extract_msg logging configuration was not found - using a basic configuration.Please check the extract_msg installation directory for "logging-z.json".FrthandlersrzDFailed to configure the logger. Did your installation get messed up?T)pathlibPath__file__parentrOrNexistsgetenvrrprintr`r" basicConfigropenrload expanduser expandvarsrPconfig dictConfigrk getLoggersetLevel) defaultPath defaultLevellogfileenableFileLoggingenv_key shippedConfignullpathsrrrrrr]tmprUs rVr!r!sLL*11F:=MMM ww$** G -- /:',,{+ K  ^$ &' )*  E D    D  IIgt $E &277>>%+@||E"  >? - . c%)nL1\\^\c\c[ddkm n dD Q1J  9  +A. . :<'':L:LGG&&'wvj?QRS?TU_?`a;ccz"1%j1Cll3'..zzKK$48z"1%j1 9!!&)    . +  TU as$9KK K L )LL cftjjjt|}tjj jt |}tjjjd|}tjjjd|}|S)zo Cleans up RTF before sending it to RTFDE. Attempts to find common sections of RTF data that will re)r8rFRTF_BODY_STRIP_PRE_OPENrH_stripRtfOpenHelperRTF_BODY_STRIP_PRE_CLOSE_stripRtfCloseHelperRTF_BODY_STRIP_INIT)rtfBodys rVr"r"sll22667JGTGll33778LgVGll..223@Gll..223@G Nrec^|jdx}jddkDr|Sd|vr|Sy)N\g<0>s \htmlrtf0r7\fs\htmlrtf}\htmlrtf0 )expandrmatchrUs rVrr s7||I&&--mI> ,T"XJ6TUVVI!!9,/I i.1 '')   + + - <!--/G'4(  ) lm  -   [ )! i.1 .KIH(%%'--/  ! dE "  emm33 4==?D c ";;t77@AD[\`ae\f[ggqrs s! 6 f    z *  #| 3OPI  #{ 2IJHQ(V# recztj|d|}|jdr|jdsyy)z Checks whether the HTML is considered valid. To be valid, the HTML must, at minimum, contain an ```` tag, a ```` tag, and closing tags for each. z html.parser) from_encodingrbodyFT)bs4 BeautifulSoupr)rr6bss rVr'r's3  4 IB 776?"''&/ rect|ts tdt|dk7r td t |dy#t $r tdwxYw)a Determines whether a property ID is valid for certain functions. Property IDs MUST be a 4 digit hexadecimal string. Property is valid if no exception is raised. :raises InvalidPropertyIdError: The ID is not a 4 digit hexadecimal number. z'ID was not a 4 digit hexadecimal stringrdN)rr`r>rintrk)ids rVr(r(+s] b# $%NOO 2w!|$%NOOP B P$%NOOPs AAcr|5|tjvr"|tjvrtd|dyyy)z Verifies that the type is valid. Raises an exception if it is not. :raises UnknownTypeError: The type is not recognized. Nz Unknown type .)r8VARIABLE_LENGTH_PROPS_STRINGFIXED_LENGTH_PROPS_STRINGr@)rs rVr)r)>sI  ?? ?eS\SvSvFv"]5'#;< <Gw ?re)rRz pathlib.PathreturnzOptional[pathlib.Path])rorBrprBrHrB)r~rrHr`)rrBrrBrHrB)rHNone)rHr-)rr`rHr`)rzDict[str, Any]rr`rHr`)rr,rrBrHz List[AnyStr])rrBrHdatetime.datetime)rorBrHfloatrZ)rrKrHrJ)rz Sequence[str]rHzargparse.Namespace)rrArH Optional[str])ror`rHr`)rMz&Union[bytes, None, str, SupportsBytes]r6r`rHr)rozconstants.MSG_PATHrHz List[str])rWzOptional[Union[str, bytes]]r6r`rHr`)rorrHbool)rMz Optional[_T]rHz#Optional[weakref.ReferenceType[_T]])r`rBrHr`)rozUnion[str, Iterable[str]]rHr`)rrBr|zUnion[int, bytes]r6r`rzSequence[bytes])rr`rHr`)rorBrrBrHrB)rrMrHrM)rrrHr)rzre.MatchrHr)rrBrUnion[str, None]rHrN)r rBrHrB)rrArHzDict[str, List])r2z(Union[bytes, str, email.message.Message]rHr.)rrr6rLrHrM)rCr`rHrI)rrLrHrI)m __future__r__all__rrrrr email.headerr email.message email.policyrrr"logging.configrOrrFrrrrZrr=rrrr*rEtypingr+r,r-r.r/r0r1r2r3r4r5r6rr8rr9 exceptionsr:r;r<r=r>r?r@msg_classes.msgrArrBr__name__r addHandler NullHandler addLevelNamerErrrrrr r r r r rrrrrrrrrrrrrrarrrrrr WARNr!r"rrrr#r$r%r&r'r(r)rrerVr]s" ' T     % !(+   8 $%'%%'(Q $ T]  -* 6H   $ ^41wh3<4 6@FA>&6,4 =   ?2"CLR%@0 $GLLDlq1K6:K\($$(B R:z~B P& =re