.\" -*- mode: troff; coding: utf-8 -*- .\" Automatically generated by Pod::Man 5.01 (Pod::Simple 3.43) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>. .ie n \{\ . ds C` "" . ds C' "" 'br\} .el\{\ . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" ======================================================================== .\" .IX Title "Dbx 3" .TH Dbx 3 2023-07-26 "perl v5.38.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH NAME Mail::Transport::Dbx \- Parse Outlook Express mailboxes .SH SYNOPSIS .IX Header "SYNOPSIS" .Vb 1 \& use Mail::Transport::Dbx; \& \& my $dbx = eval { Mail::Transport::Dbx\->new("box.mbx") }; \& die $@ if $@; \& \& for my $i (0 .. $dbx\->msgcount \- 1) { \& my $msg = $dbx\->get($i); \& print $msg\->subject; \& ... \& } \& \& # more convenient \& for my $msg ($dbx\->emails) { \& print $msg\->subject; \& ... \& } .Ve .SH ABSTRACT .IX Header "ABSTRACT" .Vb 1 \& Read dbx files (mailbox files of Outlook Express) .Ve .SH DESCRIPTION .IX Header "DESCRIPTION" Mail::Transport::Dbx gives you platform independent access to Outlook Express' dbx files. Extract subfolders, messages etc. from those or use it to convert dbx archives into a more portable format (such as standard mbox format). .PP It relies on LibDBX to do its job. The bad news: LibDBX knows nothing about the endianness of your machine so it does not work on big-endian machines such as Macintoshs or SUNs. The good news: I made the appropriate patches so that it in fact does work even on machines with the 'wrong' byteorder (exception: machines with an even odder byteorder such as Crays are not suppored; exception from the exception: If you buy me a Cray I'll promise to fix it. :\-). .PP You have to understand the structure of .dbx files to make proper use of this module. Outlook Express keeps a couple of those files on your harddisk. For instance: .PP .Vb 3 \& Folders.dbx \& folder1.dbx \& comp.lang.perl.misc.dbx .Ve .PP The nasty thing about that is that there are really two different kinds of such files: One that contains the actual messages and one that merely holds references to other .dbx files. \fIFolders.dbx\fR could be considered the toplevel file since it lists all other available .dbx files. As for folder1.dbx and comp.lang.perl.misc.dbx you can't yet know whether they contain messages or subfolders (though comp.lang.perl.misc.dbx probably contains newsgroup messages that are treated as mere emails). .PP Fortunately this module gives you the information you need. A common approach would be the following: .PP .Vb 1 \& 1) create a new Mail::Transport::Dbx object from "Folders.dbx" \& \& 2) iterate over its items using the get() method \& 2.1 if it returns a Mail::Transport::Dbx::Email \& => a message \& 2.2 if it returns a Mail::Transport::Dbx::Folder \& => a folder \& \& 3) if message \& 3.1 call whatever method from Mail::Transport::Dbx::Email \& you need \& \& 4) if folder \& 4.1 call whatever method from Mail::Transport::Dbx::Folder \& you need \& OR \& 4.2 call dbx() on it to create a new Mail::Transport::Dbx \& object \& 4.2.1 if dbx() returned something defined \& => rollback to item 2) .Ve .PP The confusing thing is that .dbx files may contain references to other folders that don't really exist! If Outlook Express was used a newsclient this is a common scenario since Folders.dbx lists \fBall\fR newsgroups as separate \f(CW\*(C`Mail::Transport::Dbx::Folder\*(C'\fR objects no matter whether you are subscribed to any of those or not. So in essence calling \f(CWdbx()\fR on a folder will only return a new object if the corresponding .dbx file exists. .SH METHODS .IX Header "METHODS" The following are methods for \fBMail::Transport::Dbx\fR objects: .IP \fBnew(filename)\fR 4 .IX Item "new(filename)" .PD 0 .IP \fBnew(filehandle\-ref)\fR 4 .IX Item "new(filehandle-ref)" .PD Passed either a string being the filename or an already opened and readable filehandle ref, \f(CWnew()\fR will construct a Mail::Transport::Dbx object from that. .Sp This happens regardless of whether you open an ordinary dbx file or the special \fIFolders.dbx\fR file that contains an overview over all available dbx subfolders. .Sp If opening fails for some reason your program will instantly \f(CWdie()\fR so be sure to wrap the constructor into an \f(CWeval()\fR and check for \f(CW$@\fR: .Sp .Vb 2 \& my $dbx = eval { Mail::Transport::Dbx\->new( "file.dbx" ) }; \& die $@ if $@; .Ve .Sp Be careful with using a filehandle, though. On Windows, you might need to use \f(CWbinmode()\fR on your handle or otherwise the stream from your dbx file might get corrupted. .IP \fBmsgcount\fR 4 .IX Item "msgcount" Returns the number of items stored in the dbx structure. If you previously opened Folders.dbx \f(CWmsgcount()\fR returns the number of subfolders in it. Otherwise it returns the number of messages. \f(CW\*(C`msgcount() \- 1\*(C'\fR is the index of the last item. .IP \fBemails\fR 4 .IX Item "emails" In list context this method returns all emails contained in the file. In boolean (that is, scalar) context it returns a true value if the file contains emails and false if it contains subfolders. .Sp .Vb 5 \& if ($dbx\->emails) { \& print "I contain emails"; \& } else { \& print "I contain subfolders"; \& } .Ve .Sp This is useful for iterations: .Sp .Vb 3 \& for my $msg ($dbx\->emails) { \& ... \& } .Ve .IP \fBsubfolders\fR 4 .IX Item "subfolders" In list context this method returns all subfolders of the current file as \f(CW\*(C`Mail::Transport::Dbx::Folder\*(C'\fR objects. In boolean (scalar) context it returns true of the file contains subfolders and false if it contains emails. .Sp Remember that you still have to call \f(CWdbx()\fR on these subfolders if you want to do something useful with them: .Sp .Vb 8 \& for my $sub ($dbx\->subfolders) { \& if (my $d = $sub\->dbx) { \& # $d now a proper Mail::Transport::Dbx object \& # with content \& } else { \& print "Subfolder referenced but non\-existent"; \& } \& } .Ve .IP \fBget(n)\fR 4 .IX Item "get(n)" Get the item at the n\-th position. First item is at position 0. \f(CWget()\fR is actually a factory method so it either returns a \f(CW\*(C`Mail::Transport::Dbx::Email\*(C'\fR or \f(CW\*(C`Mail::Transport::Dbx::Folder\*(C'\fR object. This depends on the folder you call this method upon: .Sp .Vb 2 \& my $dbx = Mail::Transport::Dbx\->new( "Folders.dbx" ); \& my $item = $dbx\->get(0); .Ve .Sp \&\f(CW$item\fR will now definitely be a \f(CW\*(C`Mail::Transport::Dbx::Folder\*(C'\fR object since \fIFolders.dbx\fR doesn't contain emails but references to subfolders. .Sp You can use the \f(CWis_email()\fR and \f(CWis_folder()\fR method to check for its type: .Sp .Vb 6 \& if ($item\->is_email) { \& print $item\->subject; \& } else { \& # it\*(Aqs a subfolder \& ... \& } .Ve .Sp On an error, this method returns an undefined value. Check \f(CW\*(C`$dbx\->errstr\*(C'\fR to find out what went wrong. .IP \fBerrstr\fR 4 .IX Item "errstr" Whenever an error occurs, \f(CWerrstr()\fR will contain a string giving you further help what went wrong. .Sp \&\fBWARNING:\fR Internally it relies on a global variable so all objects will have the same error-string! That means it only makes sense to use it after an operation that potentially raises an error: .Sp .Vb 3 \& # example 1 \& my $dbx = Mail::Transport::Dbx\->new("box.dbx") \& or die Mail::Transport::Dbx\->errstr; \& \& # example 2 \& my $msg = $dbx\->get(5) or print $dbx\->errstr; .Ve .IP \fBerror\fR 4 .IX Item "error" Similar to \f(CWerrstr()\fR, only that it will return an error code. See "Exportable constants/Error\-Codes" under "EXPORT" for codes that can be returned. .PP The following are the methods for \fBMail::Transport::Dbx::Email\fR objects: .IP \fBas_string\fR 4 .IX Item "as_string" Returns the whole message (header and body) as one large string. .Sp Note that the string still contains the raw newlines as used by DOSish systems (\e015\e012). If you want newlines to be represented in the native format of your operating system, use the following: .Sp .Vb 2 \& my $email = $msg\->as_string; \& $email =~ s/\e015\e012/\en/g; .Ve .Sp On Windows this is a no-op so you can ommit this step. .Sp Especially for news-articles this method may return \f(CW\*(C`undef\*(C'\fR. This always happens when the particular articles was only partially downloaded (that is, only header retrieved from the newsserver). There is no way to retrieve this header literally with \f(CW\*(C`header\*(C'\fR. Methods like \f(CW\*(C`subject\*(C'\fR etc. however do work. .IP \fBheader\fR 4 .IX Item "header" Returns the header-portion of the whole email. .Sp With respect to newlines the same as described under \f(CWas_string()\fR applies. .Sp Returns \f(CW\*(C`undef\*(C'\fR under the same circumstances as \f(CW\*(C`as_string\*(C'\fR. .IP \fBbody\fR 4 .IX Item "body" Returns the body-portion of the whole email. .Sp With respect to newlines the same as described under \f(CWas_string()\fR applies. .Sp Returns \f(CW\*(C`undef\*(C'\fR under the same circumstances as \f(CW\*(C`as_string\*(C'\fR. .IP \fBsubject\fR 4 .IX Item "subject" Returns the subject of the email as a string. .IP \fBpsubject\fR 4 .IX Item "psubject" Returns the processed subject of the email as a string. 'Processed' means that additions such as "Re:" etc. are cut off. .IP \fBmsgid\fR 4 .IX Item "msgid" Returns the message-id of the message as a string. .IP \fBparents_ids\fR 4 .IX Item "parents_ids" Returns the message-ids of the parent messages as a string. .IP \fBsender_name\fR 4 .IX Item "sender_name" Returns the name of the sender of this email as a string. .IP \fBsender_address\fR 4 .IX Item "sender_address" Returns the address of the sender of this email as a string. .IP \fBrecip_name\fR 4 .IX Item "recip_name" Returns the name of the recipient of this email as a string. This might be your name. ;\-) .IP \fBrecip_address\fR 4 .IX Item "recip_address" Returns the address of the recipient of this email as a string. .IP \fBoe_account_name\fR 4 .IX Item "oe_account_name" Returns the Outlook Express account name this message was retrieved with as a string. .IP \fBoe_account_num\fR 4 .IX Item "oe_account_num" Outlook Express accounts also seem to have a numerical representation. This method will return this as a string (something like "0000001"). .IP \fBfetched_server\fR 4 .IX Item "fetched_server" Returns the name of the POP server that this message was retrieved from as a string. .IP \fBrcvd_localtime\fR 4 .IX Item "rcvd_localtime" This is the exact duplicate of Perl's builtin \f(CWlocaltime()\fR applied to the date this message was received. It returns a string in scalar context and a list with nine elements in list context. See 'perldoc \-f localtime' for details. .IP \fBrcvd_gmtime\fR 4 .IX Item "rcvd_gmtime" Same as \f(CWrcvd_localtime()\fR but returning a date conforming to GMT. .IP "\fBdate_received( [format, [len, [gmtime]]] )\fR" 4 .IX Item "date_received( [format, [len, [gmtime]]] )" This method returns the date this message was received by you as a string. The date returned is calculated according to \f(CWlocaltime()\fR. .Sp Without additional arguments, the string returned looks something like .Sp .Vb 1 \& Sun Apr 14 02:27:57 2002 .Ve .Sp The optional first argument is a string describing the format of the date line. It is passed unchanged to \f(CWstrftime(3)\fR. Please consult your system's documentation for \f(CWstrftime(3)\fR to see how such a string has to look like. The default string to render the date is "%a \f(CW%b\fR \f(CW%e\fR \f(CW%H:\fR%M:%S \f(CW%Y\fR". .Sp The optional second argument is the max string length to be returned by \f(CWdate_received()\fR. This parameter is also passed unaltered to \f(CWstrftime()\fR. This method uses 25 as default .Sp The third argument can be set to a true value if you rather want to get a date in GMT. So if you want to get the GMT of the date but want to use the default rendering settings, you will have to provide them yourself: .Sp .Vb 1 \& print $msg\->date_received("%a %b %e %H:%M:%S %Y", 25, 1); .Ve .IP \fBis_seen\fR 4 .IX Item "is_seen" Returns a true value if this message has already been seen. False otherwise. .IP \fBis_email\fR 4 .IX Item "is_email" Always returns true for this kind of object. .IP \fBis_folder\fR 4 .IX Item "is_folder" Always returns false for this kind of object. .PP The following methods exist for \fBMail::Transport::Dbx::Folder\fR objects: .IP \fBdbx\fR 4 .IX Item "dbx" This is a convenience method. It creates a \f(CW\*(C`Mail::Transport::Dbx\*(C'\fR object from the folder object. If the folder is only mentioned but not physically existing on your hard-drive (either because you deleted the .dbx file or it was actually never there which especially happens for newsgroup files) \f(CW\*(C`dbx\*(C'\fR returns an undefined value. .Sp Please read "DESCRIPTION" again to learn why \f(CWdbx()\fR can return an undefined value. .IP \fBnum\fR 4 .IX Item "num" The index number of this folder. This is the number you passed to \f(CW\*(C`$dbx\->get()\*(C'\fR to retrieve this folder. .IP \fBtype\fR 4 .IX Item "type" According to \fIlibdbx.h\fR this returns one of \f(CW\*(C`DBX_TYPE_FOLDER\*(C'\fR or \f(CW\*(C`DBX_TYPE_EMAIL\*(C'\fR. Use it to check whether the folder contains emails or other folders. .IP \fBname\fR 4 .IX Item "name" The name of the folder. .IP \fBfile\fR 4 .IX Item "file" The filename of the folder. Use this, to create a new \f(CW\*(C`Mail::Transport::Dbx\*(C'\fR object: .Sp .Vb 2 \& # $folder is a Mail::Transport::Dbx::Folder object \& my $new_dbx = Mail::Transport::Dbx\->new( $folder\->file ); .Ve .Sp Consider using the \f(CWdbx()\fR method instead. .Sp This method returns an undefined value if there is no .dbx file belonging to this folder. .IP \fBid\fR 4 .IX Item "id" Numerical id of the folder. Not sure what this is useful for. .IP \fBparent_id\fR 4 .IX Item "parent_id" Numerical id of the parent's folder. .IP \fBfolder_path\fR 4 .IX Item "folder_path" Returns the full folder name of this folder as a list of path elements. It's then in your responsibility to join them together by using a delimiter that doesn't show up in any of the elements. ;\-) .Sp .Vb 1 \& print join("/", $_\->folder_path), "\en" for $dbx\->subfolders; \& \& # could for instance produce a long list, such as: \& Outlook Express/news.rwth\-aachen.de/de.comp.software.announce \& Outlook Express/news.rwth\-aachen.de/de.comp.software.misc \& ... \& Outlook Express/Lokale Ordner/test/test1 \& Outlook Express/Lokale Ordner/test \& Outlook Express/Lokale Ordner/Entwürfe \& Outlook Express/Lokale Ordner/Gelöschte Objekte \& Outlook Express/Lokale Ordner/Gesendete Objekte \& Outlook Express/Lokale Ordner/Postausgang \& Outlook Express/Lokale Ordner/Posteingang \& Outlook Express/Lokale Ordner \& Outlook Express/Outlook Express .Ve .Sp Note that a slash (as any other character) might not be a safe choice as it could show up in a folder name. .SH EXPORT .IX Header "EXPORT" None by default. .SS "Exportable constants" .IX Subsection "Exportable constants" If you intend to use any of the following constants, you have to import them when \f(CWuse()\fRing the module. You can import them all in one go thusly: .PP .Vb 1 \& use Mail::Transport::Dbx qw(:all); .Ve .PP Or you import only those you need: .PP .Vb 1 \& use Mail::Transport::Dbx qw(DBX_TYPE_EMAIL DBX_TYPE_FOLDER); .Ve .IP \fBError-Codes\fR 4 .IX Item "Error-Codes" .RS 4 .PD 0 .IP \(bu 8 .PD DBX_NOERROR .Sp No error occured. .IP \(bu 8 DBX_BADFILE .Sp Dbx file operation failed (open or close) .IP \(bu 8 DBX_DATA_READ .Sp Reading of data from dbx file failed .IP \(bu 8 DBX_INDEXCOUNT .Sp Index out of range .IP \(bu 8 DBX_INDEX_OVERREAD .Sp Request was made for index reference greater than exists .IP \(bu 8 DBX_INDEX_UNDERREAD .Sp Number of indexes read from dbx file is less than expected .IP \(bu 8 DBX_INDEX_READ .Sp Reading of Index Pointer from dbx file failed .IP \(bu 8 DBX_ITEMCOUNT .Sp Reading of Item Count from dbx file failed .IP \(bu 8 DBX_NEWS_ITEM .Sp Item is a news item not an email .RE .RS 4 .RE .IP "\fBDbx types\fR" 4 .IX Item "Dbx types" One of these is returned by \f(CW\*(C`$folder\->type\*(C'\fR so you can check whether the folder contains emails or subfolders. \fBNote that only DBX_TYPE_EMAIL and DBX_TYPE_FOLDER are ever returned so even newsgroup postings are of the type DBX_TYPE_EMAIL\fR. .RS 4 .IP \(bu 8 DBX_TYPE_EMAIL .IP \(bu 8 DBX_TYPE_FOLDER .IP \(bu 8 DBX_TYPE_NEWS .Sp Don't use this one! .IP \(bu 8 DBX_TYPE_VOID .Sp I have no idea what this is for. .RE .RS 4 .RE .IP "\fBMiscellaneous constants\fR" 4 .IX Item "Miscellaneous constants" .RS 4 .PD 0 .IP \(bu 8 .PD DBX_EMAIL_FLAG_ISSEEN .IP \(bu 8 DBX_FLAG_BODY .RE .RS 4 .RE .SH CAVEATS .IX Header "CAVEATS" You can't retrieve the internal state of the objects using \f(CW\*(C`Data::Dumper\*(C'\fR or so since \f(CW\*(C`Mail::Transport::Dbx\*(C'\fR uses a blessed scalar to hold a reference to the respective C structures. That means you have to use the provided methods for each object. Call that strong encapsultion if you need an euphemism for that. .PP There are currently no plans to implement write access to .dbx files. I leave that up to the authors of libdbx. .SH "KNOWN BUGS" .IX Header "KNOWN BUGS" Other than that I don't know yet of any. This, of course, has never actually been a strong indication for the absence of bugs. .SH "SEE ALSO" .IX Header "SEE ALSO" http://sourceforge.net/projects/ol2mbox hosts the libdbx package. It contains the library backing this module along with a description of the file format for .dbx files. .SH AUTHOR .IX Header "AUTHOR" Tassilo von Parseval, .SH "COPYRIGHT AND LICENSE" .IX Header "COPYRIGHT AND LICENSE" Copyright 2003\-2005 by Tassilo von Parseval .PP This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. .SH "POD ERRORS" .IX Header "POD ERRORS" Hey! \fBThe above document had some coding errors, which are explained below:\fR .IP "Around line 450:" 4 .IX Item "Around line 450:" Non-ASCII character seen before =encoding in 'Ordner/Entwürfe'. Assuming CP1252