Step 1 of rearranging per r129
This commit is contained in:
340
offlineimap/head/COPYING
Normal file
340
offlineimap/head/COPYING
Normal file
@ -0,0 +1,340 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
22
offlineimap/head/COPYRIGHT
Normal file
22
offlineimap/head/COPYRIGHT
Normal file
@ -0,0 +1,22 @@
|
||||
offlineimap Mail syncing software
|
||||
Copyright (C) 2002 John Goerzen
|
||||
<jgoerzen@complete.org>
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
imaplib.py comes from Python dev tree and is licensed inder the
|
||||
GPL-compatible PSF license as follows:
|
||||
|
||||
ONLY imaplib.py is Copyright (c) 2001 Python Software Foundation;
|
||||
All Rights Reserved
|
38
offlineimap/head/Makefile
Normal file
38
offlineimap/head/Makefile
Normal file
@ -0,0 +1,38 @@
|
||||
# Copyright (C) 2002 John Goerzen
|
||||
# <jgoerzen@complete.org>
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
SHELL=/bin/bash
|
||||
|
||||
clean:
|
||||
-python2.2 setup.py clean --all
|
||||
-rm -f `find . -name "*~"`
|
||||
-rm -f `find . -name "*.pyc"`
|
||||
-rm -f `find . -name "*.pygc"`
|
||||
-rm -f `find . -name "*.class"`
|
||||
-rm -f `find . -name "*.bak"`
|
||||
-rm -f `find . -name ".cache*"`
|
||||
-find . -name auth -exec rm -vf {}/password {}/username \;
|
||||
|
||||
changelog:
|
||||
cvs2cl
|
||||
cvs commit ChangeLog
|
||||
rm ChangeLog.bak
|
||||
|
||||
docs:
|
||||
man -t -l offlineimap.1 > manual.ps
|
||||
ps2pdf manual.ps
|
||||
groff -Tascii -man offlineimap.1 | sed $$'s/.\b//g' > manual.txt
|
||||
groff -Thtml -man offlineimap.1 > manual.html
|
11
offlineimap/head/README
Normal file
11
offlineimap/head/README
Normal file
@ -0,0 +1,11 @@
|
||||
OfflineIMAP
|
||||
Copyright (C) 2002 John Goerzen <jgoerzen@complete.org>
|
||||
This software comes with ABSOLUTELY NO WARRANTY; see the file
|
||||
COPYING for details. This is free software, and you are welcome
|
||||
to distribute it under the conditions laid out in COPYING.
|
||||
|
||||
gopher://quux.org/1/devel/offlineimap
|
||||
http://quux.org/devel/offlineimap
|
||||
|
||||
Please see manual.txt; the information previously in README has been moved
|
||||
there.
|
6
offlineimap/head/TODO
Normal file
6
offlineimap/head/TODO
Normal file
@ -0,0 +1,6 @@
|
||||
* Add an option to handle the network exception that results if a connection
|
||||
to the IMAP server fails, or there is another socket error.
|
||||
|
||||
* Force unidirectional sync for read-only folders.
|
||||
|
||||
* Add a -checkins mailing list.
|
196
offlineimap/head/debian/changelog
Normal file
196
offlineimap/head/debian/changelog
Normal file
@ -0,0 +1,196 @@
|
||||
offlineimap (3.0.2) unstable; urgency=low
|
||||
|
||||
* Fixed mailbox name recorder to use localfolder.getvisiblename() rather
|
||||
than remotefolder.getvisiblename()
|
||||
* Fixed remotepassfile option. Closes: #153119. Used 1-line patch from
|
||||
Tommi Virtanen.
|
||||
|
||||
-- John Goerzen <jgoerzen@complete.org> Mon, 15 Jul 2002 19:43:36 -0500
|
||||
|
||||
offlineimap (3.0.1) unstable; urgency=low
|
||||
|
||||
* Detabified the source.
|
||||
* Added UI list to the manpage.
|
||||
* Added -o (run only once) option with patch sent in by Martijn Pieters.
|
||||
* Optimized folder/IMAP.py addmessagesflags() with new listjoin() in
|
||||
imaputil. Now, send the server 1:5,7 instead of 1,2,3,4,5,7.
|
||||
* Made folder/Maildir.py/deletemessage() more tolerant if a message
|
||||
asked to be deleted already has been.
|
||||
* In Base.py/copymessageto(), no longer bother calling getmessage()
|
||||
unless a folder's storemessages() returns true. This will also help
|
||||
with syncing to LocalStatus if the user deleted messages in the
|
||||
Maildir since the cachemessagelist() was called.
|
||||
|
||||
-- John Goerzen <jgoerzen@complete.org> Fri, 12 Jul 2002 07:28:24 -0500
|
||||
|
||||
offlineimap (3.0.0) unstable; urgency=low
|
||||
|
||||
* Introduced a new graphical user interface written with Tkinter.
|
||||
It features a nice view of multi-threaded displays.
|
||||
* The TTY user interface now also displays thread names.
|
||||
* Program-wide, new threads are given descriptive names to aid in
|
||||
debugging and status messages.
|
||||
* Added new module offlineimap/ui/detect.py that is used to detect
|
||||
which user interface to select for a given session. Its operation
|
||||
is governed by the ui config option and the -u command-line option.
|
||||
* Made IMAP folder addmessagesflags() resiliant to a server refusing
|
||||
to return a full set of new message flags. Closes: #152587.
|
||||
* Completely rewrote documentation. OfflineIMAP now has an
|
||||
exhaustive manpage, which is really a manual. It is also shipped
|
||||
in plain text, HTML, PDF, and PostScript formats.
|
||||
* New command-line options:
|
||||
-1 to force no multi-threaded operation
|
||||
-u to force a particular UI
|
||||
-a to specify which accounts to sync
|
||||
-h to print help
|
||||
-c to specify an alternate config file
|
||||
* Added a workaround for UW IMAP problem wherein the server loses
|
||||
uidvalidity whenever a folder is emptied. Now, the program
|
||||
will not consider it a problem if uidvalidity is lost when a folder
|
||||
and the local status cache are both completely empty, since we do
|
||||
not really need to preserve uidvalidity in that case anyway.
|
||||
Closes: #152079.
|
||||
|
||||
-- John Goerzen <jgoerzen@complete.org> Thu, 11 Jul 2002 22:35:42 -0500
|
||||
|
||||
offlineimap (2.0.8) unstable; urgency=low
|
||||
|
||||
* Modified the IMAP folder to use SELECT rather than STATUS more often.
|
||||
Makes the code more robust; handles better with read-only folders;
|
||||
and runs faster, especially for non-threaded useres, where it
|
||||
may eliminate up to 2-3 commands per folder.
|
||||
* Made sure IMAP folder savemessage() does a select. This was a possible
|
||||
bug.
|
||||
* Modified Maildir folder to unlink messages with T flag in
|
||||
cachemessagelist()
|
||||
* My own box now syncs in 3 seconds.
|
||||
* Optimized acquireconnection() to try to give a thread back the
|
||||
connection that it last used, if possible.
|
||||
|
||||
-- John Goerzen <jgoerzen@complete.org> Tue, 9 Jul 2002 23:29:30 -0500
|
||||
|
||||
offlineimap (2.0.7) unstable; urgency=low
|
||||
|
||||
* Fixed imaplib.py to work better with read-only folders.
|
||||
|
||||
-- John Goerzen <jgoerzen@complete.org> Tue, 9 Jul 2002 20:24:21 -0500
|
||||
|
||||
offlineimap (2.0.6) unstable; urgency=low
|
||||
|
||||
* Added support for holdconnectionopen and keepalive. This feature
|
||||
allows for an IMAP server connection(s) to be held open until
|
||||
the next sync process, permitting faster restart times.
|
||||
* Another try at read-only folder support. This is nasty because I
|
||||
have no way to test it and imaplib's read-only support is weird.
|
||||
* Closing out old bug; fixed in 1.0.2. Closes: #150803.
|
||||
* Optimized algorithm so that a SELECT is never issued for folders
|
||||
that contain no messages.
|
||||
|
||||
-- John Goerzen <jgoerzen@complete.org> Tue, 9 Jul 2002 20:05:24 -0500
|
||||
|
||||
offlineimap (2.0.5) unstable; urgency=low
|
||||
|
||||
* Fixed a folderfilter example. Partially fixes #152079.
|
||||
* Added folderincludes capability. Partially fixes #152079.
|
||||
* More fixes for read-only folders.
|
||||
|
||||
-- John Goerzen <jgoerzen@complete.org> Fri, 5 Jul 2002 09:21:52 -0500
|
||||
|
||||
offlineimap (2.0.4) unstable; urgency=low
|
||||
|
||||
* Made OfflineIMAP at least rudimentarily compatible with read-only
|
||||
folders. It will still fail if they get modified locally, though.
|
||||
* Flags are handled case-insensitively. Closes: #151993.
|
||||
|
||||
-- John Goerzen <jgoerzen@complete.org> Fri, 5 Jul 2002 09:10:29 -0500
|
||||
|
||||
offlineimap (2.0.3) unstable; urgency=low
|
||||
|
||||
* Added support for specifying references. Closes: #151960.
|
||||
* Added -d command-line option to enable imaplib debugging.
|
||||
|
||||
-- John Goerzen <jgoerzen@complete.org> Thu, 4 Jul 2002 20:39:29 -0500
|
||||
|
||||
offlineimap (2.0.2) unstable; urgency=low
|
||||
|
||||
* Added support for remotepassfile. Closes: #151943.
|
||||
* Added support for preauth tunnels.
|
||||
|
||||
-- John Goerzen <jgoerzen@complete.org> Thu, 4 Jul 2002 14:46:23 -0500
|
||||
|
||||
offlineimap (2.0.1) unstable; urgency=low
|
||||
|
||||
* Fixed a bug with not properly propogating foldersep changes.
|
||||
Now, local folders and status folders properly use the foldersep
|
||||
mechanism. This corrects a problem with Exchange servers.
|
||||
* Wrote a major new thread montiring subsystem, defined a new
|
||||
ExitNotifyThread. Handling of Ctrl-C now occurs within 1 second
|
||||
rather than after the whole program terminates. Exceptions that
|
||||
occur in a thread are now caught by the main thread and marshalled
|
||||
over into the UI side of things for dispatch. The entire program will
|
||||
now abort when one thread dies with an exception.
|
||||
|
||||
-- John Goerzen <jgoerzen@complete.org> Thu, 4 Jul 2002 09:07:06 -0500
|
||||
|
||||
offlineimap (2.0.0) unstable; urgency=low
|
||||
|
||||
* This code is now multithreaded. New config file options control the
|
||||
behavior. This can make synchronizing several times faster.
|
||||
* Fixed the STATUS call to be compatible with Exchange.
|
||||
* Added the ability to exclude folders.
|
||||
* If upgrading from 1.0.x, you will need to add maxsyncaccounts to the
|
||||
general section and maxconnections to each account sections.
|
||||
There is also a new folderfilter option.
|
||||
You can find examples of all of these in the new offlineimap.conf
|
||||
example file packaged with the distribution.
|
||||
* The Debian package now properly installs the example offlineimap.conf
|
||||
file.
|
||||
* There is a new mailing list available. To join, send SUBSCRIBE
|
||||
to offlineimap-request@complete.org. The posting address is
|
||||
offlineimap@complete.org.
|
||||
|
||||
-- John Goerzen <jgoerzen@complete.org> Wed, 3 Jul 2002 19:21:32 -0500
|
||||
|
||||
offlineimap (1.0.4) unstable; urgency=low
|
||||
|
||||
* Deletion of more than one message has been optimized. This could make
|
||||
deleting large numbers of messages far faster -- several orders of
|
||||
magnitude.
|
||||
* Moved more sleep code into ui layer. Fancier sleep actions are now
|
||||
possible. Better handling of Ctrl-C in TTY handler.
|
||||
|
||||
-- John Goerzen <jgoerzen@complete.org> Tue, 2 Jul 2002 19:16:04 -0500
|
||||
|
||||
offlineimap (1.0.3) unstable; urgency=low
|
||||
|
||||
* Fixed a bug when a message was deleted on the IMAP side and modified
|
||||
on the local side.
|
||||
|
||||
-- John Goerzen <jgoerzen@complete.org> Mon, 24 Jun 2002 19:08:21 -0500
|
||||
|
||||
offlineimap (1.0.2) unstable; urgency=low
|
||||
|
||||
* Made sure that LocalStatus does writing atomically. If the program
|
||||
is interrupted during save(), there will always be a complete copy of
|
||||
either the old or the new data.
|
||||
|
||||
-- John Goerzen <jgoerzen@complete.org> Mon, 24 Jun 2002 06:57:28 -0500
|
||||
|
||||
offlineimap (1.0.1) unstable; urgency=low
|
||||
|
||||
* Fixed a bug with writing messages to some IMAP servers. Turns
|
||||
out we need to issue CHECK between APPEND and SEARCH for some.
|
||||
Thanks to Donovan Lange for reporting this bug and helping track it
|
||||
down.
|
||||
|
||||
-- John Goerzen <jgoerzen@complete.org> Fri, 21 Jun 2002 22:03:12 -0500
|
||||
|
||||
offlineimap (1.0.0) unstable; urgency=low
|
||||
|
||||
* Initial Release. Closes: #150571.
|
||||
|
||||
-- John Goerzen <jgoerzen@complete.org> Fri, 21 Jun 2002 18:54:56 -0500
|
||||
|
||||
Local variables:
|
||||
mode: debian-changelog
|
||||
End:
|
39
offlineimap/head/debian/control
Normal file
39
offlineimap/head/debian/control
Normal file
@ -0,0 +1,39 @@
|
||||
Source: offlineimap
|
||||
Section: mail
|
||||
Priority: optional
|
||||
Maintainer: John Goerzen <jgoerzen@complete.org>
|
||||
Build-Depends-Indep: debhelper (>> 3.0.0), python2.2 (>= 2.2.1-4)
|
||||
Standards-Version: 3.5.2
|
||||
|
||||
Package: offlineimap
|
||||
Architecture: all
|
||||
Depends: python2.2
|
||||
Suggests: python2.2-tk
|
||||
Description: IMAP/Maildir synchronization and reader support
|
||||
OfflineIMAP is a tool to simplify your e-mail reading. With
|
||||
OfflimeIMAP, you can:
|
||||
.
|
||||
* Read the same mailbox from multiple computers, and have your
|
||||
changes (deletions, etc.) be automatically reflected on
|
||||
all computers
|
||||
.
|
||||
* Use various mail clients to read a single mail box
|
||||
.
|
||||
* Read mail while offline (on a laptop) and have all changes
|
||||
synchronized when you get connected again
|
||||
.
|
||||
* Read IMAP mail with mail readers that do not support IMAP
|
||||
.
|
||||
* Use SSL (secure connections) to read IMAP mail even if your reader
|
||||
doesn't support SSL
|
||||
.
|
||||
* Synchronize your mail using a completely safe and fault-tolerant
|
||||
algorithm. (At least I think it is!)
|
||||
.
|
||||
* Customize which mailboxes to synchronize with regular expressions
|
||||
or lists.
|
||||
.
|
||||
* Synchronize your mail two to four times faster than with other tools
|
||||
or other mail readers' internal IMAP support.
|
||||
.
|
||||
In short, OfflineIMAP is a tool to let you read mail how YOU want to.
|
23
offlineimap/head/debian/copyright
Normal file
23
offlineimap/head/debian/copyright
Normal file
@ -0,0 +1,23 @@
|
||||
This is offlineimap, written and maintained by John Goerzen <jgoerzen@complete.org>
|
||||
on Fri, 21 Jun 2002 14:54:56 -0500.
|
||||
|
||||
The original source can always be found at:
|
||||
ftp://ftp.debian.org/dists/unstable/main/source/
|
||||
|
||||
Copyright (C) 2002 John Goerzen
|
||||
|
||||
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 with
|
||||
the Debian GNU/Linux distribution in file /usr/share/common-licenses/GPL-2;
|
||||
if not, write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
Suite 330, Boston, MA 02111-1307 USA
|
||||
|
2
offlineimap/head/debian/dirs
Normal file
2
offlineimap/head/debian/dirs
Normal file
@ -0,0 +1,2 @@
|
||||
usr/bin
|
||||
usr/sbin
|
5
offlineimap/head/debian/docs
Normal file
5
offlineimap/head/debian/docs
Normal file
@ -0,0 +1,5 @@
|
||||
manual.txt
|
||||
manual.ps
|
||||
manual.pdf
|
||||
manual.html
|
||||
|
101
offlineimap/head/debian/rules
Normal file
101
offlineimap/head/debian/rules
Normal file
@ -0,0 +1,101 @@
|
||||
#!/usr/bin/make -f
|
||||
# Sample debian/rules that uses debhelper.
|
||||
# GNU copyright 1997 to 1999 by Joey Hess.
|
||||
# Modified by John Goerzen
|
||||
|
||||
# Uncomment this to turn on verbose mode.
|
||||
#export DH_VERBOSE=1
|
||||
|
||||
# This is the debhelper compatibility version to use.
|
||||
export DH_COMPAT=3
|
||||
|
||||
PYTHON=python2.2
|
||||
PACKAGE=offlineimap
|
||||
|
||||
|
||||
ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS)))
|
||||
CFLAGS += -g
|
||||
endif
|
||||
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||
INSTALL_PROGRAM += -s
|
||||
endif
|
||||
|
||||
configure: configure-stamp
|
||||
configure-stamp:
|
||||
dh_testdir
|
||||
# Add here commands to configure the package.
|
||||
#$(PYTHON) setup.py configure
|
||||
|
||||
touch configure-stamp
|
||||
|
||||
|
||||
build: build-stamp
|
||||
|
||||
build-stamp: configure-stamp
|
||||
dh_testdir
|
||||
|
||||
# Add here commands to compile the package.
|
||||
$(PYTHON) setup.py build
|
||||
#/usr/bin/docbook-to-man debian/pygopherd.sgml > pygopherd.1
|
||||
|
||||
touch build-stamp
|
||||
|
||||
clean:
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
rm -f build-stamp configure-stamp
|
||||
|
||||
# Add here commands to clean up after the build process.
|
||||
-$(MAKE) clean
|
||||
|
||||
dh_clean
|
||||
|
||||
install: build
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_clean -k
|
||||
dh_installdirs
|
||||
|
||||
# Add here commands to install the package into debian/pygopherd.
|
||||
#$(MAKE) install DESTDIR=$(CURDIR)/debian/pygopherd
|
||||
$(PYTHON) setup.py install --root=`pwd`/debian/$(PACKAGE) --no-compile
|
||||
|
||||
|
||||
# Build architecture-dependent files here.
|
||||
binary-arch: build install
|
||||
# We have nothing to do by default.
|
||||
|
||||
# Build architecture-independent files here.
|
||||
binary-indep: build install
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
# dh_installdebconf
|
||||
dh_installdocs
|
||||
mv debian/$(PACKAGE)/usr/bin/$(PACKAGE).py \
|
||||
debian/$(PACKAGE)/usr/bin/$(PACKAGE)
|
||||
dh_installexamples offlineimap.conf
|
||||
dh_installmenu
|
||||
# dh_installlogrotate
|
||||
# dh_installemacsen
|
||||
# dh_installpam
|
||||
# dh_installmime
|
||||
dh_installinit
|
||||
dh_installcron
|
||||
dh_installman offlineimap.1
|
||||
dh_installinfo
|
||||
# dh_undocumented
|
||||
dh_installchangelogs
|
||||
dh_link
|
||||
dh_strip
|
||||
dh_compress
|
||||
dh_fixperms
|
||||
# dh_makeshlibs
|
||||
dh_installdeb
|
||||
# dh_perl
|
||||
dh_shlibdeps
|
||||
dh_gencontrol
|
||||
dh_md5sums
|
||||
dh_builddeb
|
||||
|
||||
binary: binary-indep binary-arch
|
||||
.PHONY: build clean binary-indep binary-arch binary install configure
|
982
offlineimap/head/manual.html
Normal file
982
offlineimap/head/manual.html
Normal file
@ -0,0 +1,982 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta name="generator" content="groff -Thtml, see www.gnu.org">
|
||||
<meta name="Content-Style" content="text/css">
|
||||
<title>OFFLINEIMAP</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1 align=center>OFFLINEIMAP</h1>
|
||||
<a href="#NAME">NAME</a><br>
|
||||
<a href="#SYNOPSIS">SYNOPSIS</a><br>
|
||||
<a href="#DESCRIPTION">DESCRIPTION</a><br>
|
||||
<a href="#INSTALLATION">INSTALLATION</a><br>
|
||||
<a href="#CONFIGURATION">CONFIGURATION</a><br>
|
||||
<a href="#OPTIONS">OPTIONS</a><br>
|
||||
<a href="#EXAMPLES">EXAMPLES</a><br>
|
||||
<a href="#ERRORS">ERRORS</a><br>
|
||||
<a href="#OTHER FREQUENTLY ASKED QUESTIONS">OTHER FREQUENTLY ASKED QUESTIONS</a><br>
|
||||
<a href="#CONFORMING TO">CONFORMING TO</a><br>
|
||||
<a href="#NOTES">NOTES</a><br>
|
||||
<a href="#BUGS">BUGS</a><br>
|
||||
<a href="#COPYRIGHT">COPYRIGHT</a><br>
|
||||
<a href="#AUTHOR">AUTHOR</a><br>
|
||||
<a href="#SEE ALSO">SEE ALSO</a><br>
|
||||
|
||||
<hr>
|
||||
<!-- Creator : groff version 1.17.2 -->
|
||||
<!-- CreationDate: Mon Jul 15 11:26:37 2002 -->
|
||||
<a name="NAME"></a>
|
||||
<h2>NAME</h2>
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
OfflineIMAP - Powerful IMAP/Maildir synchronization and reader support</td></table>
|
||||
<a name="SYNOPSIS"></a>
|
||||
<h2>SYNOPSIS</h2>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>offlineimap</b> [ <b>-1</b> ] [ <b>-a</b>
|
||||
<i>accountlist</i> ] [ <b>-c</b> <i>configfile</i> ]<br>
|
||||
[ <b>-d</b> ] [ <b>-o</b> ] [ <b>-u</b> <i>interface</i>
|
||||
]</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>offlineimap -h</b> | <b>--help</b></td></table>
|
||||
<a name="DESCRIPTION"></a>
|
||||
<h2>DESCRIPTION</h2>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>OfflineIMAP</b> is a tool to simplify your e-mail
|
||||
reading. With <b>OfflineIMAP,</b> you can read the same
|
||||
mailbox from multiple computers. You get a current copy of
|
||||
your messages on each computer, and changes you make one
|
||||
place will be visible on all other systems. For instance,
|
||||
you can delete a message on your home computer, and it will
|
||||
appear deleted on your work computer as well.
|
||||
<b>OfflineIMAP</b> is also useful if you want to use a mail
|
||||
reader that does not have IMAP support, has poor IMAP
|
||||
support, or does not provide disconnected
|
||||
operation.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>OfflineIMAP</b> is <i>FAST;</i> it synchronizes my two
|
||||
accounts with over 50 folders in 3 seconds. Other similar
|
||||
tools might take over a minute, and achieve a less-reliable
|
||||
result. Some mail readers can take over 10 minutes to do the
|
||||
same thing, and some don't even support it at all. Unlike
|
||||
other mail tools, <b>OfflineIMAP</b> features a
|
||||
multi-threaded synchronization algorithm that can
|
||||
dramatically speed up performance in many situations by
|
||||
synchronizing several different things
|
||||
simultaneously.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>OfflineIMAP</b> is <i>FLEXIBLE;</i> you can customize
|
||||
which folders are synced via regular expressions, lists, or
|
||||
Python expressions; a versatile and comprehensive
|
||||
configuration file is used to control behavior; two user
|
||||
interfaces are built-in; fine-tuning of synchronization
|
||||
performance is possible; internal or external automation is
|
||||
supported; SSL and PREAUTH tunnels are both supported;
|
||||
offline (or "unplugged") reading is supported; and
|
||||
esoteric IMAP features are supported to ensure compatibility
|
||||
with the widest variety of IMAP servers.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>OfflineIMAP</b> is <i>SAFE;</i> it uses an algorithm
|
||||
designed to prevent mail loss at all costs. Because of the
|
||||
design of this algorithm, even programming errors should not
|
||||
result in loss of mail. I am so confident in the algorithm
|
||||
that I use my own personal and work accounts for testing of
|
||||
<b>OfflineIMAP</b> pre-release, development, and beta
|
||||
releases.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="4%"></td><td width="96%">
|
||||
<b>METHOD OF OPERATION</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>OfflineIMAP</b> operates by maintaining a hierarchy of
|
||||
mail folders in Maildir format locally. Your own mail reader
|
||||
will read mail from this tree, and need never know that the
|
||||
mail comes from IMAP. <b>OfflineIMAP</b> will detect changes
|
||||
to the mail folders on your IMAP server and your own
|
||||
computer and bi-directionally synchronize them, copying,
|
||||
marking, and deleting messages as necessary.</td></table>
|
||||
<a name="INSTALLATION"></a>
|
||||
<h2>INSTALLATION</h2>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
If you are reading this document via the "man"
|
||||
command, it is likely that you have no installation tasks to
|
||||
perform; your system administrator has already installed it.
|
||||
If you need to install it yourself, you have three options:
|
||||
a system-wide installation with Debian, system-wide
|
||||
installation with other systems, and a single-user
|
||||
installation. You can download the latest version of
|
||||
OfflineIMAP from
|
||||
http://quux.org/devel/offlineimap/.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="4%"></td><td width="96%">
|
||||
<b>PREREQUISITES</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
In order to use OfflineIMAP, you need to have these
|
||||
conditions satisfied:</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
Your mail server must support IMAP. Most Internet Service
|
||||
Providers and corporate networks do, and most operating
|
||||
systems have an IMAP implementation readily
|
||||
available.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
You must have Python version 2.2.1 or above installed. If
|
||||
you are running on Debian GNU/Linux, this requirement will
|
||||
automatically be taken care of for you. If you do not have
|
||||
Python already, check with your system administrator or
|
||||
operating system vendor; or, download it from
|
||||
http://www.python.org/. If you intend to use the Tk
|
||||
interface, you must have Tkiner (python-tk) installed. If
|
||||
you intend to use the SSL interface, your Python must have
|
||||
been built with SSL support.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
Have a mail reader that supports the Maildir mailbox format.
|
||||
Most modern mail readers have this support built-in, so you
|
||||
can choose from a wide variety of mail servers. This format
|
||||
is also known as the "qmail" format, so any mail
|
||||
reader compatible with it will work with
|
||||
OfflineIMAP.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="4%"></td><td width="96%">
|
||||
<b>DEBIAN SYSTEM-WIDE INSTALLATION</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
If you are tracking Debian unstable, you may install
|
||||
<b>OfflineIMAP</b> by simply running the following command
|
||||
as root:</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>apt-get install offlineimap</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
If you are not tracking Debian unstable, download the Debian
|
||||
.deb package from the OfflineIMAP website and then run
|
||||
<b>dpkg -i</b> to install the downloaded package. Then, go
|
||||
to CONFIGURATION below. You will type <b>offlineimap</b> to
|
||||
invoke the program.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="4%"></td><td width="96%">
|
||||
<b>OTHER SYSTEM-WIDE INSTALLATION</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
Download the tar.gz version of the package from the website.
|
||||
Then run these commands:</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>tar -zxvf offlineimap-x.y.z.tar.gz<br>
|
||||
cd offlineimap-x.y.z<br>
|
||||
python2.2 setup.py</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
Some systems will need to use <b>python</b> instead of
|
||||
<b>python2.2.</b> Next, proceed to configuration. You will
|
||||
type <b>offlineimap</b> to invoke the program.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="4%"></td><td width="96%">
|
||||
<b>SINGLE-ACCOUNT INSTALLATION</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
Download the tar.gz version of the package from the website.
|
||||
Then run these commands:</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>tar -zxvf offlineimap-x.y.z.tar.gz<br>
|
||||
cd offlineimap-x.y.z</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
When you want to run <b>OfflineIMAP,</b> you will issue the
|
||||
<b>cd</b> command as above and then type
|
||||
<b>./offlineimap;</b> there is no installation step
|
||||
necessary.</td></table>
|
||||
<a name="CONFIGURATION"></a>
|
||||
<h2>CONFIGURATION</h2>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>OfflineIMAP</b> is regulated by a configuration file that
|
||||
is normally stored in <i>~/.offlineimaprc.</i>
|
||||
<b>OfflineIMAP</b> ships with a file named
|
||||
<i>offlineimap.conf</i> that you should copy to that
|
||||
location and then edit. This file is vital to proper
|
||||
operation of the system; it sets everything you need to run
|
||||
<b>OfflineIMAP.</b> Full documentation for the configuration
|
||||
file is included within the sample file.</td></table>
|
||||
<a name="OPTIONS"></a>
|
||||
<h2>OPTIONS</h2>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
Most configuration is done via the configuration file.
|
||||
Nevertheless, there are a few options that you may set for
|
||||
<b>OfflineIMAP.</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>-1</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
Disable all multithreading operations and use solely a
|
||||
single-thread sync. This effectively sets the
|
||||
<b>maxsyncaccounts</b> and all <b>maxconnections</b>
|
||||
configuration file variables to 1.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>-a</b> <i>accountlist</i></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
Overrides the <b>accounts</b> section in the config file.
|
||||
Lets you specify a particular account or set of accounts to
|
||||
sync without having to edit the config file. You might use
|
||||
this to exclude certain accounts, or to sync some accounts
|
||||
that you normally prefer not to.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>-c</b> <i>configfile</i></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
Specifies a configuration file to use in lieu of the
|
||||
default, <i>~/.offlineimaprc.</i></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>-d</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
Enables IMAP protocol stream and parsing debugging. This is
|
||||
useful if you are trying to track down a malfunction or
|
||||
figure out what is going on under the hood. I suggest that
|
||||
you use this with <b>-1</b> in order to make the results
|
||||
more sensible. Note that this output will contain full IMAP
|
||||
protocol in plain text, including passwords, so take care to
|
||||
remove that from the debugging output before sending it to
|
||||
anyone else.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>-o</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
Run only once, ignoring any autorefresh setting in the
|
||||
config file.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>-h, --help</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
Show summary of options.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>-u</b> <i>interface</i></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
Specifies an alternative user interface module to use. This
|
||||
overrides the default specified in the configuration file.
|
||||
The UI specified with <b>-u</b> will be forced to be used,
|
||||
even if its <b>isuable()</b> method states that it cannot
|
||||
be. Use this option with care.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
The pre-defined options are <b>Tk.TKUI</b> (a graphical
|
||||
interface) and <b>TTY.TTYUI</b> (a text-mode
|
||||
interface).</td></table>
|
||||
<a name="EXAMPLES"></a>
|
||||
<h2>EXAMPLES</h2>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
Here is an example configuration for a particularly complex
|
||||
situation; more examples will be added later.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="4%"></td><td width="96%">
|
||||
<b>MULTIPLE ACCOUNTS WITH MUTT</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
This example shows you how to set up <b>OfflineIMAP</b> to
|
||||
synchronize multiple accounts with the mutt mail
|
||||
reader.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
Start by creating a directory to hold your folders:<b><br>
|
||||
mkdir ~/Mail</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
In your <i>~/.offlineimaprc,</i> specify this:<b><br>
|
||||
accounts = Personal, Work</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
Make sure that you have both a <b>[Personal]</b> and a
|
||||
<b>[Work]</b> section, with different localfolder pathnames
|
||||
and enable <b>[mbnames].</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
In each account section, do something like this:<b><br>
|
||||
localfolders = ~/Mail/Personal</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
Add these lines to your <i>~/.muttrc:</i><b><br>
|
||||
source ~/path-to-mbnames-muttrc-mailboxes<br>
|
||||
folder-hook Personal set
|
||||
from="youremail@personal.com"<br>
|
||||
folder-hook Work set from="youremail@work.com"<br>
|
||||
set mbox_type=Maildir<br>
|
||||
set folder=$HOME/Mail<br>
|
||||
set spoolfile=+Personal/INBOX</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
That's it!</td></table>
|
||||
<a name="ERRORS"></a>
|
||||
<h2>ERRORS</h2>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
If you get one of some frequently-encountered or confusing
|
||||
errors, please check this section.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="4%"></td><td width="96%">
|
||||
<b>UID validity problem for folder</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
IMAP servers use a unique ID (UID) to refer to a specific
|
||||
message. This number is guaranteed to be unique to a
|
||||
particular message FOREVER. No other message in the same
|
||||
folder will ever get the same UID. UIDs are an integral part
|
||||
of OfflineIMAP's synchronization scheme; they are used to
|
||||
match up messages on your computer to messages on the
|
||||
server.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
Sometimes, the UIDs on the server might get reset. Usually
|
||||
this will happen if you delete and then recreate a folder.
|
||||
When you create a folder, the server will often start the
|
||||
UID back from 1. But <b>OfflineIMAP</b> might still have the
|
||||
UIDs from the previous folder by the same name stored.
|
||||
<b>OfflineIMAP</b> will detect this condition and skip the
|
||||
folder. This is GOOD, because it prevents data
|
||||
loss.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
You can fix it by removing your local folder and cache data.
|
||||
For instance, if your folders are under <i>~/Folders</i> and
|
||||
the folder with the problem is INBOX, you'd type
|
||||
this:</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>rm -r ~/Folders/INBOX<br>
|
||||
rm ~/.offlineimap/AccountName/INBOX</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
(replacing AccountName with the account name as specified in
|
||||
<i>~/.offlineimaprc)</i></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
Next time you run <b>OfflineIMAP,</b> it will re-download
|
||||
the folder with the new UIDs. Note that the procedure
|
||||
specified above will lose any local changes made to the
|
||||
folder.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
Some IMAP servers are broken and do not support UIDs
|
||||
properly. If you continue to get this error for all your
|
||||
folders even after performing the above procedure, it is
|
||||
likely that your IMAP server falls into this category.
|
||||
<b>OfflineIMAP</b> is incompatible with such servers. Using
|
||||
<b>OfflineIMAP</b> with them will not destroy any mail, but
|
||||
at the same time, it will not actually synchronize it
|
||||
either. (OfflineIMAP will detect this condition and abort
|
||||
prior to synchronization)</td></table>
|
||||
<a name="OTHER FREQUENTLY ASKED QUESTIONS"></a>
|
||||
<h2>OTHER FREQUENTLY ASKED QUESTIONS</h2>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
There are some other FAQs that might not fit into another
|
||||
section of this document, and they are enumerated
|
||||
here.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>What platforms does OfflineIMAP run on?</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
It should run on most platforms supported by Python, which
|
||||
are quite a few.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>I'm using Mutt. Other IMAP sync programs require me to
|
||||
use set maildir_trash=yes . Do I need to do that with
|
||||
OfflineIMAP?</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
No. <b>OfflineIMAP</b> is smart enough to figure out message
|
||||
deletion without this extra crutch. You'll get the best
|
||||
results if you don't use this setting, in fact.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>How do I specify the names of my
|
||||
folders?</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
You do not need to. <b>OfflineIMAP</b> is smart enough to
|
||||
automatically figure out what folders are present on the
|
||||
IMAP server and synchronize them. You can use the
|
||||
<b>folderfilter</b> and <b>foldertrans</b> configuration
|
||||
file options to request certain folders and rename them as
|
||||
they come in if you like.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>How can I prevent certain folders from being
|
||||
synced?</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
Use the <b>folderfilter</b> option in the configuration
|
||||
file.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>How can I add or delete a folder?</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
<b>OfflineIMAP</b> does not currently provide this feature,
|
||||
but if you create a new folder on the IMAP server, it will
|
||||
be created locally automatically.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>Are there any other warnings that I should be aware
|
||||
of?</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
Yes; see the NOTES section below.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>What is the mailbox name recorder (mbnames)
|
||||
for?</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
The Mutt mail reader is not capable of automatically
|
||||
determining the names of your mailboxes. OfflineIMAP can
|
||||
help it (or many other) programs out be writing these names
|
||||
out in a format you specify. See the example
|
||||
offlineimap.conf file for details.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>Can I synchronize multiple accounts with
|
||||
OfflineIMAP?</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
Sure. Just name them all in the accounts line in the general
|
||||
section of the config file, and add a per-account section
|
||||
for each one.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>Does OfflineIMAP support POP?</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
No. POP is not robust enough to do a completely reliable
|
||||
multi-machine synchronization like OfflineIMAP can do.
|
||||
OfflineIMAP will not support it.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>Do you support mailbox formats other than
|
||||
Maildir?</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
Not at present. There is no technical reason not to; just no
|
||||
demand yet. Maildir is a superior format
|
||||
anyway.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>[technical] Why are your Maildir message filenames so
|
||||
huge?</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
<b>OfflineIMAP</b> has two relevant principles: 1) never
|
||||
modifying your messages in any way and 2) ensuring 100%
|
||||
reliable synchronizations. In order to do a reliable sync,
|
||||
<b>OfflineIMAP</b> must have a way to uniquely identify each
|
||||
e-mail. Three pieces of information are required to do this:
|
||||
your account name, the folder name, and the message UID. The
|
||||
account name can be calculated from the path in which your
|
||||
messages are. The folder name can usually be as well, BUT
|
||||
some mail clients move messages between folders by simply
|
||||
moving the file, leaving the name intact.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
So, <b>OfflineIMAP</b> must store both a UID folder ID. The
|
||||
folder ID is necessary so <b>OfflineIMAP</b> can detect a
|
||||
message moved to a different folder. <b>OfflineIMAP</b>
|
||||
stores the UID (U= number) and an md5sum of the foldername
|
||||
(FMD5= number) to facilitate this.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>What is the speed of OfflineIMAP's sync?</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
<b>OfflineIMAP</b> versions 2.0 and above contain a
|
||||
multithreaded system. A good way to experiment is by setting
|
||||
maxsyncaccounts to 3 and maxconnections to 3 in each account
|
||||
clause.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
This lets OfflineIMAP open up multiple connections
|
||||
simultaneously. That will let it process multiple folders
|
||||
and messages at once. In most cases, this will increase
|
||||
performance of the sync.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
Don't set the number too high. If you do that, things might
|
||||
actually slow down as your link gets saturated. Also, too
|
||||
many connections can cause mail servers to have excessive
|
||||
load. Administrators might take unkindly to this, and the
|
||||
server might bog down. There are many variables in the
|
||||
optimal setting; experimentation may help.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
An informal benchmark yields these results for my
|
||||
setup:</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
10 minutes with MacOS X Mail.app "manual
|
||||
cache"<br>
|
||||
5 minutes with GNUS agent sync<br>
|
||||
20 seconds with OfflineIMAP 1.x<br>
|
||||
9 seconds with OfflineIMAP 2.x<br>
|
||||
3 seconds with OfflineIMAP 3.x "cold start"<br>
|
||||
2 seconds with OfflineIMAP 3.x "held
|
||||
connection"</td></table>
|
||||
<a name="CONFORMING TO"></a>
|
||||
<h2>CONFORMING TO</h2>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
Internet Message Access Protocol version 4rev1 (IMAP 4rev1)
|
||||
as specified in RFC2060</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
Maildir as specified in
|
||||
http://www.qmail.org/qmail-manual-html/man5/maildir.html and
|
||||
http://cr.yp.to/proto/maildir.html.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="21%"></td><td width="79%">
|
||||
Standard Python 2.2.1 as implemented on POSIX-compliant
|
||||
systems.</td></table>
|
||||
<a name="NOTES"></a>
|
||||
<h2>NOTES</h2>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="4%"></td><td width="96%">
|
||||
<b>DELETING LOCAL FOLDERS</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>OfflineIMAP</b> does a two-way synchronization. That is,
|
||||
if you make a change to the mail on the server, it will be
|
||||
propogated to your local copy, and vise-versa. Some people
|
||||
might think that it would be wise to just delete all their
|
||||
local mail folders periodically. If you do this with
|
||||
OfflineIMAP, remember to also remove your local status cache
|
||||
(~/.offlineimap by default). Otherwise, OfflineIMAP will
|
||||
take this as an intentional deletion of many messages and
|
||||
will interpret your action as requesting them to be deleted
|
||||
from the server as well. (If you don't understand this,
|
||||
don't worry; you probably won't encounter this
|
||||
situation)</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="4%"></td><td width="96%">
|
||||
<b>MAILING LIST</b></td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
There is an OfflineIMAP mailing list available.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
To subscribe, send the text "Subscribe" in the
|
||||
subject of a mail to offlineimap-request@complete.org. To
|
||||
post, send the message to
|
||||
offlineimap@complete.org.</td></table>
|
||||
<a name="BUGS"></a>
|
||||
<h2>BUGS</h2>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
Should be reported to the author at the address specified
|
||||
below.</td></table>
|
||||
<a name="COPYRIGHT"></a>
|
||||
<h2>COPYRIGHT</h2>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
OfflineIMAP is Copyright (C) 2002 John Goerzen.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
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.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
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.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with this program; if not, write
|
||||
to:</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
Free Software Foundation, Inc.<br>
|
||||
59 Temple Place<br>
|
||||
Suite 330<br>
|
||||
Boston, MA 02111-1307<br>
|
||||
USA</td></table>
|
||||
<a name="AUTHOR"></a>
|
||||
<h2>AUTHOR</h2>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>OfflineIMAP,</b> its libraries, documentation, and all
|
||||
included files, except where noted, was written by John
|
||||
Goerzen <jgoerzen@complete.org> and copyright is held
|
||||
as stated in the COPYRIGHT section.</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
OfflineIMAP may be downloaded, and information found, from
|
||||
its homepage via either Gopher or HTTP:</td></table>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
gopher://quux.org/1/devel/offlineimap<br>
|
||||
http://quux.org/devel/offlineimap</td></table>
|
||||
<a name="SEE ALSO"></a>
|
||||
<h2>SEE ALSO</h2>
|
||||
|
||||
<table width="100%" border=0 rules="none" frame="void"
|
||||
cols="2" cellspacing="0" cellpadding="0">
|
||||
<tr valign="top" align="left">
|
||||
<td width="10%"></td><td width="90%">
|
||||
<b>mutt</b>(1), <b>python</b>(1).</td></table>
|
||||
<hr>
|
||||
</body>
|
||||
</html>
|
BIN
offlineimap/head/manual.pdf
Normal file
BIN
offlineimap/head/manual.pdf
Normal file
Binary file not shown.
711
offlineimap/head/manual.ps
Normal file
711
offlineimap/head/manual.ps
Normal file
@ -0,0 +1,711 @@
|
||||
%!PS-Adobe-3.0
|
||||
%%Creator: groff version 1.17.2
|
||||
%%CreationDate: Mon Jul 15 11:26:30 2002
|
||||
%%DocumentNeededResources: font Times-Roman
|
||||
%%+ font Times-Bold
|
||||
%%+ font Times-Italic
|
||||
%%DocumentSuppliedResources: procset grops 1.17 2
|
||||
%%Pages: 6
|
||||
%%PageOrder: Ascend
|
||||
%%Orientation: Portrait
|
||||
%%EndComments
|
||||
%%BeginProlog
|
||||
%%BeginResource: procset grops 1.17 2
|
||||
/setpacking where{
|
||||
pop
|
||||
currentpacking
|
||||
true setpacking
|
||||
}if
|
||||
/grops 120 dict dup begin
|
||||
/SC 32 def
|
||||
/A/show load def
|
||||
/B{0 SC 3 -1 roll widthshow}bind def
|
||||
/C{0 exch ashow}bind def
|
||||
/D{0 exch 0 SC 5 2 roll awidthshow}bind def
|
||||
/E{0 rmoveto show}bind def
|
||||
/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def
|
||||
/G{0 rmoveto 0 exch ashow}bind def
|
||||
/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
|
||||
/I{0 exch rmoveto show}bind def
|
||||
/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def
|
||||
/K{0 exch rmoveto 0 exch ashow}bind def
|
||||
/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
|
||||
/M{rmoveto show}bind def
|
||||
/N{rmoveto 0 SC 3 -1 roll widthshow}bind def
|
||||
/O{rmoveto 0 exch ashow}bind def
|
||||
/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
|
||||
/Q{moveto show}bind def
|
||||
/R{moveto 0 SC 3 -1 roll widthshow}bind def
|
||||
/S{moveto 0 exch ashow}bind def
|
||||
/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def
|
||||
/SF{
|
||||
findfont exch
|
||||
[exch dup 0 exch 0 exch neg 0 0]makefont
|
||||
dup setfont
|
||||
[exch/setfont cvx]cvx bind def
|
||||
}bind def
|
||||
/MF{
|
||||
findfont
|
||||
[5 2 roll
|
||||
0 3 1 roll
|
||||
neg 0 0]makefont
|
||||
dup setfont
|
||||
[exch/setfont cvx]cvx bind def
|
||||
}bind def
|
||||
/level0 0 def
|
||||
/RES 0 def
|
||||
/PL 0 def
|
||||
/LS 0 def
|
||||
/MANUAL{
|
||||
statusdict begin/manualfeed true store end
|
||||
}bind def
|
||||
/PLG{
|
||||
gsave newpath clippath pathbbox grestore
|
||||
exch pop add exch pop
|
||||
}bind def
|
||||
/BP{
|
||||
/level0 save def
|
||||
1 setlinecap
|
||||
1 setlinejoin
|
||||
72 RES div dup scale
|
||||
LS{
|
||||
90 rotate
|
||||
}{
|
||||
0 PL translate
|
||||
}ifelse
|
||||
1 -1 scale
|
||||
}bind def
|
||||
/EP{
|
||||
level0 restore
|
||||
showpage
|
||||
}bind def
|
||||
/DA{
|
||||
newpath arcn stroke
|
||||
}bind def
|
||||
/SN{
|
||||
transform
|
||||
.25 sub exch .25 sub exch
|
||||
round .25 add exch round .25 add exch
|
||||
itransform
|
||||
}bind def
|
||||
/DL{
|
||||
SN
|
||||
moveto
|
||||
SN
|
||||
lineto stroke
|
||||
}bind def
|
||||
/DC{
|
||||
newpath 0 360 arc closepath
|
||||
}bind def
|
||||
/TM matrix def
|
||||
/DE{
|
||||
TM currentmatrix pop
|
||||
translate scale newpath 0 0 .5 0 360 arc closepath
|
||||
TM setmatrix
|
||||
}bind def
|
||||
/RC/rcurveto load def
|
||||
/RL/rlineto load def
|
||||
/ST/stroke load def
|
||||
/MT/moveto load def
|
||||
/CL/closepath load def
|
||||
/FL{
|
||||
currentgray exch setgray fill setgray
|
||||
}bind def
|
||||
/BL/fill load def
|
||||
/LW/setlinewidth load def
|
||||
/RE{
|
||||
findfont
|
||||
dup maxlength 1 index/FontName known not{1 add}if dict begin
|
||||
{
|
||||
1 index/FID ne{def}{pop pop}ifelse
|
||||
}forall
|
||||
/Encoding exch def
|
||||
dup/FontName exch def
|
||||
currentdict end definefont pop
|
||||
}bind def
|
||||
/DEFS 0 def
|
||||
/EBEGIN{
|
||||
moveto
|
||||
DEFS begin
|
||||
}bind def
|
||||
/EEND/end load def
|
||||
/CNT 0 def
|
||||
/level1 0 def
|
||||
/PBEGIN{
|
||||
/level1 save def
|
||||
translate
|
||||
div 3 1 roll div exch scale
|
||||
neg exch neg exch translate
|
||||
0 setgray
|
||||
0 setlinecap
|
||||
1 setlinewidth
|
||||
0 setlinejoin
|
||||
10 setmiterlimit
|
||||
[]0 setdash
|
||||
/setstrokeadjust where{
|
||||
pop
|
||||
false setstrokeadjust
|
||||
}if
|
||||
/setoverprint where{
|
||||
pop
|
||||
false setoverprint
|
||||
}if
|
||||
newpath
|
||||
/CNT countdictstack def
|
||||
userdict begin
|
||||
/showpage{}def
|
||||
}bind def
|
||||
/PEND{
|
||||
clear
|
||||
countdictstack CNT sub{end}repeat
|
||||
level1 restore
|
||||
}bind def
|
||||
end def
|
||||
/setpacking where{
|
||||
pop
|
||||
setpacking
|
||||
}if
|
||||
%%EndResource
|
||||
%%IncludeResource: font Times-Roman
|
||||
%%IncludeResource: font Times-Bold
|
||||
%%IncludeResource: font Times-Italic
|
||||
grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72
|
||||
def/PL 792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron
|
||||
/scaron/zcaron/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef
|
||||
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
|
||||
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
|
||||
/.notdef/.notdef/space/exclam/quotedbl/numbersign/dollar/percent
|
||||
/ampersand/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen
|
||||
/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon
|
||||
/semicolon/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O
|
||||
/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/circumflex
|
||||
/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y
|
||||
/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase/guillemotleft
|
||||
/guillemotright/bullet/florin/fraction/perthousand/dagger/daggerdbl
|
||||
/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut
|
||||
/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash
|
||||
/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen
|
||||
/brokenbar/section/dieresis/copyright/ordfeminine/guilsinglleft
|
||||
/logicalnot/minus/registered/macron/degree/plusminus/twosuperior
|
||||
/threesuperior/acute/mu/paragraph/periodcentered/cedilla/onesuperior
|
||||
/ordmasculine/guilsinglright/onequarter/onehalf/threequarters
|
||||
/questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE
|
||||
/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex
|
||||
/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
|
||||
/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn
|
||||
/germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla
|
||||
/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis
|
||||
/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide/oslash
|
||||
/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis]def
|
||||
/Times-Italic@0 ENC0/Times-Italic RE/Times-Bold@0 ENC0/Times-Bold RE
|
||||
/Times-Roman@0 ENC0/Times-Roman RE
|
||||
%%EndProlog
|
||||
%%Page: 1 1
|
||||
%%BeginPageSetup
|
||||
BP
|
||||
%%EndPageSetup
|
||||
/F0 10/Times-Roman@0 SF 111.22(OFFLINEIMAP\(1\) Of)72 48 R
|
||||
(\215ineIMAP manual)-.25 E(OFFLINEIMAP\(1\))113.72 E/F1 10.95
|
||||
/Times-Bold@0 SF -.219(NA)72 84 S(ME).219 E F0(Of)108 96 Q
|
||||
(\215ineIMAP \255 Po)-.25 E
|
||||
(werful IMAP/Maildir synchronization and reader support)-.25 E F1
|
||||
(SYNOPSIS)72 112.8 Q/F2 10/Times-Bold@0 SF(of\215ineimap)108 124.8 Q F0
|
||||
([)2.5 E F2<ad31>2.5 E F0 2.5(][)2.5 G F2<ad61>A/F3 10/Times-Italic@0 SF
|
||||
(accountlist)2.5 E F0 2.5(][)2.5 G F2<ad63>A F3(con\214g\214le)2.5 E F0
|
||||
(])2.5 E([)108 136.8 Q F2<ad64>2.5 E F0 2.5(][)2.5 G F2<ad6f>A F0 2.5
|
||||
(][)2.5 G F2<ad75>A F3(interface)2.5 E F0(])2.5 E F2
|
||||
(of\215ineimap \255h)108 160.8 Q F0(|)2.5 E F2(\255\255help)2.5 E F1
|
||||
(DESCRIPTION)72 177.6 Q F2(Of\215ineIMAP)108 189.6 Q F0 .019
|
||||
(is a tool to simplify your e-mail reading.)2.519 F -.4(Wi)5.019 G(th).4
|
||||
E F2(Of\215ineIMAP)2.519 E(,)-.92 E F0 .018
|
||||
(you can read the same mailbox)2.519 F 1.115(from multiple computers.)
|
||||
108 201.6 R -1.1(Yo)6.115 G 3.615(ug)1.1 G 1.115(et a current cop)-3.615
|
||||
F 3.616(yo)-.1 G 3.616(fy)-3.616 G 1.116(our messages on each computer)
|
||||
-3.616 F 3.616(,a)-.4 G 1.116(nd changes you)-3.616 F(mak)108 213.6 Q
|
||||
2.915(eo)-.1 G .414(ne place will be visible on all other systems.)
|
||||
-2.915 F -.15(Fo)5.414 G 2.914(ri).15 G .414
|
||||
(nstance, you can delete a message on your home)-2.914 F(computer)108
|
||||
225.6 Q 3.5(,a)-.4 G 1(nd it will appear deleted on your w)-3.5 F 1
|
||||
(ork computer as well.)-.1 F F2(Of\215ineIMAP)6 E F0 1
|
||||
(is also useful if you)3.5 F -.1(wa)108 237.6 S .827
|
||||
(nt to use a mail reader that does not ha).1 F 1.127 -.15(ve I)-.2 H
|
||||
.827(MAP support, has poor IMAP support, or does not pro).15 F(vide)-.15
|
||||
E(disconnected operation.)108 249.6 Q F2(Of\215ineIMAP)108 266.4 Q F0
|
||||
(is)3.216 E F3 -1.15(FA)3.216 G(ST)1.15 E(;)-.65 E F0 .716
|
||||
(it synchronizes my tw)3.216 F 3.216(oa)-.1 G .716(ccounts with o)-3.216
|
||||
F -.15(ve)-.15 G 3.216(r5).15 G 3.216(0f)-3.216 G .717
|
||||
(olders in 3 seconds.)-3.216 F .717(Other similar)5.717 F .26
|
||||
(tools might tak)108 278.4 R 2.76(eo)-.1 G -.15(ve)-2.91 G 2.76(ram).15
|
||||
G .26(inute, and achie)-2.76 F .56 -.15(ve a l)-.25 H .259
|
||||
(ess-reliable result.).15 F .259(Some mail readers can tak)5.259 F 2.759
|
||||
(eo)-.1 G -.15(ve)-2.909 G 2.759(r1).15 G 2.759(0m)-2.759 G(in-)-2.759 E
|
||||
.157(utes to do the same thing, and some don')108 290.4 R 2.657(te)-.18
|
||||
G -.15(ve)-2.907 G 2.657(ns).15 G .157(upport it at all.)-2.657 F(Unlik)
|
||||
5.158 E 2.658(eo)-.1 G .158(ther mail tools,)-2.658 F F2(Of\215ineIMAP)
|
||||
2.658 E F0(fea-)2.658 E .321(tures a multi-threaded synchronization alg\
|
||||
orithm that can dramatically speed up performance in man)108 302.4 R
|
||||
2.82(ys)-.15 G(itu-)-2.82 E(ations by synchronizing se)108 314.4 Q -.15
|
||||
(ve)-.25 G(ral dif).15 E(ferent things simultaneously)-.25 E(.)-.65 E F2
|
||||
(Of\215ineIMAP)108 331.2 Q F0(is)3.065 E F3(FLEXIBLE;)3.065 E F0 .566
|
||||
(you can customize which folders are synced via re)3.065 F .566(gular e)
|
||||
-.15 F .566(xpressions, lists, or)-.15 F .734(Python e)108 343.2 R .734
|
||||
(xpressions; a v)-.15 F .734(ersatile and comprehensi)-.15 F 1.034 -.15
|
||||
(ve c)-.25 H .733(on\214guration \214le is used to control beha).15 F
|
||||
.733(vior; tw)-.2 F 3.233(ou)-.1 G(ser)-3.233 E(interf)108 355.2 Q .535
|
||||
(aces are b)-.1 F .535(uilt-in; \214ne-tuning of synchronization perfor\
|
||||
mance is possible; internal or e)-.2 F .535(xternal automa-)-.15 F .441
|
||||
(tion is supported; SSL and PREA)108 367.2 R .441
|
||||
(UTH tunnels are both supported; of)-.55 F .44
|
||||
(\215ine \(or "unplugged"\) reading is sup-)-.25 F .543(ported; and eso\
|
||||
teric IMAP features are supported to ensure compatibility with the wide\
|
||||
st v)108 379.2 R .544(ariety of IMAP)-.25 F(serv)108 391.2 Q(ers.)-.15 E
|
||||
F2(Of\215ineIMAP)108 408 Q F0(is)4.065 E F3(SAFE;)4.065 E F0 1.565
|
||||
(it uses an algorithm designed to pre)4.065 F -.15(ve)-.25 G 1.565
|
||||
(nt mail loss at all costs.).15 F 1.564(Because of the)6.564 F .01
|
||||
(design of this algorithm, e)108 420 R -.15(ve)-.25 G 2.51(np).15 G .01
|
||||
(rogramming errors should not result in loss of mail.)-2.51 F 2.511(Ia)
|
||||
5.011 G 2.511(ms)-2.511 G 2.511(oc)-2.511 G .011(on\214dent in the)
|
||||
-2.511 F .448(algorithm that I use my o)108 432 R .448
|
||||
(wn personal and w)-.25 F .448(ork accounts for testing of)-.1 F F2
|
||||
(Of\215ineIMAP)2.948 E F0 .448(pre-release, de)2.948 F -.15(ve)-.25 G
|
||||
(lop-).15 E(ment, and beta releases.)108 444 Q F2(METHOD OF OPERA)87
|
||||
460.8 Q(TION)-.95 E(Of\215ineIMAP)108 472.8 Q F0 .07
|
||||
(operates by maintaining a hierarch)2.57 F 2.57(yo)-.05 G 2.57(fm)-2.57
|
||||
G .07(ail folders in Maildir format locally)-2.57 F 5.07(.Y)-.65 G .07
|
||||
(our o)-6.17 F .07(wn mail)-.25 F .618
|
||||
(reader will read mail from this tree, and need ne)108 484.8 R -.15(ve)
|
||||
-.25 G 3.118(rk).15 G(no)-3.118 E 3.118(wt)-.25 G .617
|
||||
(hat the mail comes from IMAP)-3.118 F(.)-1.11 E F2(Of\215ineIMAP)5.617
|
||||
E F0 .849(will detect changes to the mail folders on your IMAP serv)108
|
||||
496.8 R .849(er and your o)-.15 F .849(wn computer and bi-directionally)
|
||||
-.25 F(synchronize them, cop)108 508.8 Q
|
||||
(ying, marking, and deleting messages as necessary)-.1 E(.)-.65 E F1
|
||||
(INST)72 525.6 Q(ALLA)-.986 E(TION)-1.04 E F0 .491
|
||||
(If you are reading this document via the "man" command, it is lik)108
|
||||
537.6 R .49(ely that you ha)-.1 F .79 -.15(ve n)-.2 H 2.99(oi).15 G .49
|
||||
(nstallation tasks to)-2.99 F .043
|
||||
(perform; your system administrator has already installed it.)108 549.6
|
||||
R .044(If you need to install it yourself, you ha)5.043 F .344 -.15
|
||||
(ve t)-.2 H(hree).15 E .39(options: a system-wide installation with Deb\
|
||||
ian, system-wide installation with other systems, and a single-)108
|
||||
561.6 R 12.823(user installation.)108 573.6 R -1.1(Yo)17.823 G 15.323
|
||||
(uc)1.1 G 12.823(an do)-15.323 F 12.823(wnload the latest v)-.25 F
|
||||
12.823(ersion of Of)-.15 F 12.823(\215ineIMAP from)-.25 F
|
||||
(http://quux.or)108 585.6 Q(g/de)-.18 E -.15(ve)-.25 G(l/of).15 E
|
||||
(\215ineimap/.)-.25 E F2(PREREQ)87 602.4 Q(UISITES)-.1 E F0
|
||||
(In order to use Of)108 614.4 Q(\215ineIMAP)-.25 E 2.5(,y)-1.11 G
|
||||
(ou need to ha)-2.5 E .3 -.15(ve t)-.2 H(hese conditions satis\214ed:)
|
||||
.15 E 32.5<8359>108 631.2 S .197(our mail serv)-33.6 F .197
|
||||
(er must support IMAP)-.15 F 5.197(.M)-1.11 G .197
|
||||
(ost Internet Service Pro)-5.197 F .197(viders and corporate netw)-.15 F
|
||||
.196(orks do,)-.1 F(and most operating systems ha)144 643.2 Q .3 -.15
|
||||
(ve a)-.2 H 2.5(nI).15 G(MAP implementation readily a)-2.5 E -.25(va)-.2
|
||||
G(ilable.).25 E 32.5<8359>108 660 S .085(ou must ha)-33.6 F .385 -.15
|
||||
(ve P)-.2 H .085(ython v).15 F .085(ersion 2.2.1 or abo)-.15 F .385 -.15
|
||||
(ve i)-.15 H 2.585(nstalled. If).15 F .086
|
||||
(you are running on Debian GNU/Linux,)2.585 F .813
|
||||
(this requirement will automatically be tak)144 672 R .813
|
||||
(en care of for you.)-.1 F .812(If you do not ha)5.812 F 1.112 -.15
|
||||
(ve P)-.2 H .812(ython already).15 F(,)-.65 E 3.88
|
||||
(check with your system administrator or operating system v)144 684 R
|
||||
3.88(endor; or)-.15 F 6.38(,d)-.4 G -.25(ow)-6.38 G 3.88(nload it from)
|
||||
.25 F(http://www)144 696 Q(.p)-.65 E(ython.or)-.1 E 3.378(g/. If)-.18 F
|
||||
.878(you intend to use the Tk interf)3.378 F .877(ace, you must ha)-.1 F
|
||||
1.177 -.15(ve T)-.2 H .877(kiner \(p).15 F(ython-tk\))-.1 E 2.859
|
||||
(installed. If)144 708 R .359(you intend to use the SSL interf)2.859 F
|
||||
.359(ace, your Python must ha)-.1 F .66 -.15(ve b)-.2 H .36(een b).15 F
|
||||
.36(uilt with SSL sup-)-.2 F(port.)144 720 Q(John Goerzen)72 768 Q
|
||||
(July 12, 2002)151.655 E(1)201.915 E EP
|
||||
%%Page: 2 2
|
||||
%%BeginPageSetup
|
||||
BP
|
||||
%%EndPageSetup
|
||||
/F0 10/Times-Roman@0 SF 111.22(OFFLINEIMAP\(1\) Of)72 48 R
|
||||
(\215ineIMAP manual)-.25 E(OFFLINEIMAP\(1\))113.72 E 32.5<8348>108 84 S
|
||||
-2.25 -.2(av e)-32.5 H 2.784(am)2.984 G .284
|
||||
(ail reader that supports the Maildir mailbox format.)-2.784 F .284
|
||||
(Most modern mail readers ha)5.284 F .584 -.15(ve t)-.2 H(his).15 E .111
|
||||
(support b)144 96 R .112(uilt-in, so you can choose from a wide v)-.2 F
|
||||
.112(ariety of mail serv)-.25 F 2.612(ers. This)-.15 F .112
|
||||
(format is also kno)2.612 F(wn)-.25 E(as the "qmail" format, so an)144
|
||||
108 Q 2.5(ym)-.15 G(ail reader compatible with it will w)-2.5 E
|
||||
(ork with Of)-.1 E(\215ineIMAP)-.25 E(.)-1.11 E/F1 10/Times-Bold@0 SF
|
||||
(DEBIAN SYSTEM-WIDE INST)87 124.8 Q(ALLA)-.9 E(TION)-.95 E F0 .708
|
||||
(If you are tracking Debian unstable, you may install)108 136.8 R F1
|
||||
(Of\215ineIMAP)3.208 E F0 .708(by simply running the follo)3.208 F .708
|
||||
(wing com-)-.25 F(mand as root:)108 148.8 Q F1
|
||||
(apt-get install of\215ineimap)108 165.6 Q F0 .339
|
||||
(If you are not tracking Debian unstable, do)108 182.4 R .34
|
||||
(wnload the Debian .deb package from the Of)-.25 F .34
|
||||
(\215ineIMAP website)-.25 F .39(and then run)108 194.4 R F1 .39(dpkg -i)
|
||||
2.89 F F0 .389(to install the do)2.89 F .389(wnloaded package.)-.25 F
|
||||
.389(Then, go to CONFIGURA)5.389 F .389(TION belo)-1.11 F 4.189 -.65
|
||||
(w. Y)-.25 H .389(ou will)-.45 F(type)108 206.4 Q F1(of\215ineimap)2.5 E
|
||||
F0(to in)2.5 E -.2(vo)-.4 G .2 -.1(ke t).2 H(he program.).1 E F1 -.4(OT)
|
||||
87 223.2 S(HER SYSTEM-WIDE INST).4 E(ALLA)-.9 E(TION)-.95 E F0(Do)108
|
||||
235.2 Q(wnload the tar)-.25 E(.gz v)-.55 E
|
||||
(ersion of the package from the website.)-.15 E
|
||||
(Then run these commands:)5 E F1(tar -zxvf of\215ineimap-x.y)108 252 Q
|
||||
(.z.tar)-.7 E(.gz)-1 E(cd of\215ineimap-x.y)108 264 Q(.z)-.7 E
|
||||
(python2.2 setup.py)108 276 Q F0 1.272(Some systems will need to use)108
|
||||
292.8 R F1(python)3.773 E F0 1.273(instead of)3.773 F F1(python2.2.)
|
||||
3.773 E F0(Ne)6.273 E 1.273(xt, proceed to con\214guration.)-.15 F -1.1
|
||||
(Yo)6.273 G 3.773(uw)1.1 G(ill)-3.773 E(type)108 304.8 Q F1
|
||||
(of\215ineimap)2.5 E F0(to in)2.5 E -.2(vo)-.4 G .2 -.1(ke t).2 H
|
||||
(he program.).1 E F1(SINGLE-A)87 321.6 Q(CCOUNT INST)-.55 E(ALLA)-.9 E
|
||||
(TION)-.95 E F0(Do)108 333.6 Q(wnload the tar)-.25 E(.gz v)-.55 E
|
||||
(ersion of the package from the website.)-.15 E
|
||||
(Then run these commands:)5 E F1(tar -zxvf of\215ineimap-x.y)108 350.4 Q
|
||||
(.z.tar)-.7 E(.gz)-1 E(cd of\215ineimap-x.y)108 362.4 Q(.z)-.7 E F0 .149
|
||||
(When you w)108 379.2 R .149(ant to run)-.1 F F1(Of\215ineIMAP)2.648 E
|
||||
(,)-.92 E F0 .148(you will issue the)2.648 F F1(cd)2.648 E F0 .148
|
||||
(command as abo)2.648 F .448 -.15(ve a)-.15 H .148(nd then type).15 F F1
|
||||
(./of\215ineimap;)2.648 E F0(there is no installation step necessary)108
|
||||
391.2 Q(.)-.65 E/F2 10.95/Times-Bold@0 SF(CONFIGURA)72 408 Q(TION)-1.04
|
||||
E F1(Of\215ineIMAP)108 420 Q F0 .508(is re)3.008 F .508
|
||||
(gulated by a con\214guration \214le that is normally stored in)-.15 F
|
||||
/F3 10/Times-Italic@0 SF(~/.of)3.009 E(\215ineimapr)-.18 E(c.)-.37 E F1
|
||||
(Of\215ineIMAP)5.509 E F0 .004(ships with a \214le named)108 432 R F3
|
||||
(of)2.503 E(\215ineimap.conf)-.18 E F0 .003(that you should cop)2.503 F
|
||||
2.503(yt)-.1 G 2.503(ot)-2.503 G .003(hat location and then edit.)-2.503
|
||||
F .003(This \214le is vital)5.003 F .255
|
||||
(to proper operation of the system; it sets e)108 444 R -.15(ve)-.25 G
|
||||
.256(rything you need to run).15 F F1(Of\215ineIMAP)2.756 E(.)-1.1 E F0
|
||||
.256(Full documentation for)5.256 F
|
||||
(the con\214guration \214le is included within the sample \214le.)108
|
||||
456 Q F2(OPTIONS)72 472.8 Q F0 .061
|
||||
(Most con\214guration is done via the con\214guration \214le.)108 484.8
|
||||
R(Ne)5.061 E -.15(ve)-.25 G .061(rtheless, there are a fe).15 F 2.561
|
||||
(wo)-.25 G .061(ptions that you may set)-2.561 F(for)108 496.8 Q F1
|
||||
(Of\215ineIMAP)2.5 E(.)-1.1 E<ad31>108 513.6 Q F0 .281(Disable all mult\
|
||||
ithreading operations and use solely a single-thread sync.)25.3 F .281
|
||||
(This ef)5.281 F(fecti)-.25 E -.15(ve)-.25 G .281(ly sets the).15 F F1
|
||||
(maxsyncaccounts)144 525.6 Q F0(and all)2.5 E F1(maxconnections)2.5 E F0
|
||||
(con\214guration \214le v)2.5 E(ariables to 1.)-.25 E F1<ad61>108 542.4
|
||||
Q F3(accountlist)2.5 E F0(Ov)144 554.4 Q .84(errides the)-.15 F F1
|
||||
(accounts)3.34 E F0 .84(section in the con\214g \214le.)3.34 F .84
|
||||
(Lets you specify a particular account or set of)5.84 F 1.647
|
||||
(accounts to sync without ha)144 566.4 R 1.647
|
||||
(ving to edit the con\214g \214le.)-.2 F -1.1(Yo)6.648 G 4.148(um)1.1 G
|
||||
1.648(ight use this to e)-4.148 F 1.648(xclude certain)-.15 F
|
||||
(accounts, or to sync some accounts that you normally prefer not to.)144
|
||||
578.4 Q F1<ad63>108 595.2 Q F3(con\214g\214le)2.5 E F0
|
||||
(Speci\214es a con\214guration \214le to use in lieu of the def)144
|
||||
607.2 Q(ault,)-.1 E F3(~/.of)2.5 E(\215ineimapr)-.18 E(c.)-.37 E F1
|
||||
<ad64>108 624 Q F0 1.139(Enables IMAP protocol stream and parsing deb)
|
||||
24.74 F 3.639(ugging. This)-.2 F 1.138
|
||||
(is useful if you are trying to track)3.639 F(do)144 636 Q .081
|
||||
(wn a malfunction or \214gure out what is going on under the hood.)-.25
|
||||
F 2.582(Is)5.082 G .082(uggest that you use this with)-2.582 F F1<ad31>
|
||||
144 648 Q F0 .336(in order to mak)2.836 F 2.836(et)-.1 G .335
|
||||
(he results more sensible.)-2.836 F .335
|
||||
(Note that this output will contain full IMAP proto-)5.335 F 1.7
|
||||
(col in plain te)144 660 R 1.7(xt, including passw)-.15 F 1.7
|
||||
(ords, so tak)-.1 F 4.2(ec)-.1 G 1.7(are to remo)-4.2 F 2 -.15(ve t)-.15
|
||||
H 1.7(hat from the deb).15 F 1.7(ugging output)-.2 F
|
||||
(before sending it to an)144 672 Q(yone else.)-.15 E F1<ad6f>108 688.8 Q
|
||||
F0(Run only once, ignoring an)25.3 E 2.5(ya)-.15 G
|
||||
(utorefresh setting in the con\214g \214le.)-2.5 E F1
|
||||
(\255h, \255\255help)108 705.6 Q F0(Sho)144 717.6 Q 2.5(ws)-.25 G
|
||||
(ummary of options.)-2.5 E(John Goerzen)72 768 Q(July 12, 2002)151.655 E
|
||||
(2)201.915 E EP
|
||||
%%Page: 3 3
|
||||
%%BeginPageSetup
|
||||
BP
|
||||
%%EndPageSetup
|
||||
/F0 10/Times-Roman@0 SF 111.22(OFFLINEIMAP\(1\) Of)72 48 R
|
||||
(\215ineIMAP manual)-.25 E(OFFLINEIMAP\(1\))113.72 E/F1 10/Times-Bold@0
|
||||
SF<ad75>108 84 Q/F2 10/Times-Italic@0 SF(interface)2.5 E F0 1.133
|
||||
(Speci\214es an alternati)144 96 R 1.433 -.15(ve u)-.25 H 1.133
|
||||
(ser interf).15 F 1.133(ace module to use.)-.1 F 1.133(This o)6.133 F
|
||||
-.15(ve)-.15 G 1.133(rrides the def).15 F 1.132(ault speci\214ed in the)
|
||||
-.1 F .28(con\214guration \214le.)144 108 R .28(The UI speci\214ed with)
|
||||
5.28 F F1(-u)2.78 E F0 .281(will be forced to be used, e)2.78 F -.15(ve)
|
||||
-.25 G 2.781(ni).15 G 2.781(fi)-2.781 G(ts)-2.781 E F1(isuable\(\))2.781
|
||||
E F0(method)2.781 E(states that it cannot be.)144 120 Q
|
||||
(Use this option with care.)5 E .158(The pre-de\214ned options are)144
|
||||
136.8 R F1(Tk.TKUI)2.658 E F0 .158(\(a graphical interf)2.658 F .157
|
||||
(ace\) and)-.1 F F1(TTY)2.657 E(.TTYUI)-.92 E F0 .157(\(a te)2.657 F
|
||||
.157(xt-mode inter)-.15 F(-)-.2 E -.1(fa)144 148.8 S(ce\).).1 E/F3 10.95
|
||||
/Times-Bold@0 SF(EXAMPLES)72 165.6 Q F0(Here is an e)108 177.6 Q
|
||||
(xample con\214guration for a particularly comple)-.15 E 2.5(xs)-.15 G
|
||||
(ituation; more e)-2.5 E(xamples will be added later)-.15 E(.)-.55 E F1
|
||||
(MUL)87 194.4 Q(TIPLE A)-.92 E(CCOUNTS WITH MUTT)-.55 E F0 .513(This e)
|
||||
108 206.4 R .513(xample sho)-.15 F .513(ws you ho)-.25 F 3.014(wt)-.25 G
|
||||
3.014(os)-3.014 G .514(et up)-3.014 F F1(Of\215ineIMAP)3.014 E F0 .514
|
||||
(to synchronize multiple accounts with the mutt mail)3.014 F(reader)108
|
||||
218.4 Q(.)-.55 E(Start by creating a directory to hold your folders:)108
|
||||
235.2 Q F1(mkdir ~/Mail)108 247.2 Q F0(In your)108 264 Q F2(~/.of)2.5 E
|
||||
(\215ineimapr)-.18 E(c,)-.37 E F0(specify this:)2.5 E F1(accounts = P)
|
||||
108 276 Q(ersonal, W)-.2 E(ork)-.75 E F0(Mak)108 292.8 Q 2.821(es)-.1 G
|
||||
.321(ure that you ha)-2.821 F .621 -.15(ve b)-.2 H .321(oth a).15 F F1
|
||||
([P)2.821 E(ersonal])-.2 E F0 .321(and a)2.821 F F1([W)2.821 E(ork])-.75
|
||||
E F0 .32(section, with dif)2.82 F .32(ferent localfolder pathnames and)
|
||||
-.25 F(enable)108 304.8 Q F1([mbnames].)2.5 E F0
|
||||
(In each account section, do something lik)108 321.6 Q 2.5(et)-.1 G
|
||||
(his:)-2.5 E F1(localf)108 333.6 Q(olders = ~/Mail/P)-.25 E(ersonal)-.2
|
||||
E F0(Add these lines to your)108 350.4 Q F2(~/.muttr)2.5 E(c:)-.37 E F1
|
||||
(sour)108 362.4 Q(ce ~/path-to-mbnames-muttr)-.18 E(c-mailboxes)-.18 E
|
||||
-.25(fo)108 374.4 S(lder).25 E(-hook P)-.37 E(ersonal set fr)-.2 E
|
||||
(om="y)-.18 E(our)-.25 E(email@personal.com")-.18 E -.25(fo)108 386.4 S
|
||||
(lder).25 E(-hook W)-.37 E(ork set fr)-.75 E(om="y)-.18 E(our)-.25 E
|
||||
(email@w)-.18 E(ork.com")-.1 E(set mbox_type=Maildir)108 398.4 Q(set f)
|
||||
108 410.4 Q(older=$HOME/Mail)-.25 E(set spool\214le=+P)108 422.4 Q
|
||||
(ersonal/INBO)-.2 E(X)-.4 E F0(That')108 439.2 Q 2.5(si)-.55 G(t!)-2.5 E
|
||||
F3(ERR)72 456 Q(ORS)-.329 E F0(If you get one of some frequently-encoun\
|
||||
tered or confusing errors, please check this section.)108 468 Q F1
|
||||
(UID v)87 484.8 Q(alidity pr)-.1 E(oblem f)-.18 E(or f)-.25 E(older)-.25
|
||||
E F0 1.637(IMAP serv)108 496.8 R 1.637
|
||||
(ers use a unique ID \(UID\) to refer to a speci\214c message.)-.15 F
|
||||
1.638(This number is guaranteed to be)6.637 F 1.11
|
||||
(unique to a particular message FOREVER.)108 508.8 R 1.109
|
||||
(No other message in the same folder will e)6.11 F -.15(ve)-.25 G 3.609
|
||||
(rg).15 G 1.109(et the same)-3.609 F 2.873(UID. UIDs)108 520.8 R .373
|
||||
(are an inte)2.873 F .373(gral part of Of)-.15 F(\215ineIMAP')-.25 E
|
||||
2.873(ss)-.55 G .373(ynchronization scheme; the)-2.873 F 2.873(ya)-.15 G
|
||||
.373(re used to match up mes-)-2.873 F
|
||||
(sages on your computer to messages on the serv)108 532.8 Q(er)-.15 E(.)
|
||||
-.55 E .108(Sometimes, the UIDs on the serv)108 549.6 R .108
|
||||
(er might get reset.)-.15 F .108
|
||||
(Usually this will happen if you delete and then recreate)5.108 F 3.742
|
||||
(af)108 561.6 S(older)-3.742 E 6.242(.W)-.55 G 1.242
|
||||
(hen you create a folder)-6.242 F 3.742(,t)-.4 G 1.242(he serv)-3.742 F
|
||||
1.242(er will often start the UID back from 1.)-.15 F(But)6.243 E F1
|
||||
(Of\215ineIMAP)3.743 E F0 .303(might still ha)108 573.6 R .603 -.15
|
||||
(ve t)-.2 H .303(he UIDs from the pre).15 F .302
|
||||
(vious folder by the same name stored.)-.25 F F1(Of\215ineIMAP)5.302 E
|
||||
F0 .302(will detect this)2.802 F(condition and skip the folder)108 585.6
|
||||
Q 5(.T)-.55 G(his is GOOD, because it pre)-5 E -.15(ve)-.25 G
|
||||
(nts data loss.).15 E -1.1(Yo)108 602.4 S 2.826(uc)1.1 G .326
|
||||
(an \214x it by remo)-2.826 F .327
|
||||
(ving your local folder and cache data.)-.15 F -.15(Fo)5.327 G 2.827(ri)
|
||||
.15 G .327(nstance, if your folders are under)-2.827 F F2(~/F)2.827 E
|
||||
(old-)-1.05 E(er)108 614.4 Q(s)-.1 E F0
|
||||
(and the folder with the problem is INBO)2.5 E(X, you')-.4 E 2.5(dt)-.5
|
||||
G(ype this:)-2.5 E F1(rm -r ~/F)108 631.2 Q(olders/INBO)-.25 E(X)-.4 E
|
||||
(rm ~/.of\215ineimap/AccountName/INBO)108 643.2 Q(X)-.4 E F0
|
||||
(\(replacing AccountName with the account name as speci\214ed in)108 660
|
||||
Q F2(~/.of)2.5 E(\215ineimapr)-.18 E(c\))-.37 E F0(Ne)108 676.8 Q .802
|
||||
(xt time you run)-.15 F F1(Of\215ineIMAP)3.302 E(,)-.92 E F0 .802
|
||||
(it will re-do)3.302 F .802(wnload the folder with the ne)-.25 F 3.302
|
||||
(wU)-.25 G 3.301(IDs. Note)-3.302 F .801(that the proce-)3.301 F
|
||||
(dure speci\214ed abo)108 688.8 Q .3 -.15(ve w)-.15 H(ill lose an).15 E
|
||||
2.5(yl)-.15 G(ocal changes made to the folder)-2.5 E(.)-.55 E .522
|
||||
(Some IMAP serv)108 705.6 R .522(ers are brok)-.15 F .522
|
||||
(en and do not support UIDs properly)-.1 F 5.522(.I)-.65 G 3.022(fy)
|
||||
-5.522 G .522(ou continue to get this error for all)-3.022 F .067
|
||||
(your folders e)108 717.6 R -.15(ve)-.25 G 2.566(na).15 G .066
|
||||
(fter performing the abo)-2.566 F .366 -.15(ve p)-.15 H .066
|
||||
(rocedure, it is lik).15 F .066(ely that your IMAP serv)-.1 F .066(er f)
|
||||
-.15 F .066(alls into this cat-)-.1 F -.15(eg)108 729.6 S(ory).15 E(.)
|
||||
-.65 E F1(Of\215ineIMAP)5.983 E F0 .984(is incompatible with such serv)
|
||||
3.483 F 3.484(ers. Using)-.15 F F1(Of\215ineIMAP)3.484 E F0 .984
|
||||
(with them will not destro)3.484 F(y)-.1 E(John Goerzen)72 768 Q
|
||||
(July 12, 2002)151.655 E(3)201.915 E EP
|
||||
%%Page: 4 4
|
||||
%%BeginPageSetup
|
||||
BP
|
||||
%%EndPageSetup
|
||||
/F0 10/Times-Roman@0 SF 111.22(OFFLINEIMAP\(1\) Of)72 48 R
|
||||
(\215ineIMAP manual)-.25 E(OFFLINEIMAP\(1\))113.72 E(an)108 84 Q 2.77
|
||||
(ym)-.15 G .27(ail, b)-2.77 F .27
|
||||
(ut at the same time, it will not actually synchronize it either)-.2 F
|
||||
5.269(.\()-.55 G(Of)-5.269 E .269(\215ineIMAP will detect this con-)-.25
|
||||
F(dition and abort prior to synchronization\))108 96 Q/F1 10.95
|
||||
/Times-Bold@0 SF -.438(OT)72 124.8 S(HER FREQ).438 E(UENTL)-.11 E 2.738
|
||||
(YA)-1.007 G(SKED Q)-2.738 E(UESTIONS)-.11 E F0 .683
|
||||
(There are some other F)108 136.8 R -.55(AQ)-.74 G 3.184(st).55 G .684
|
||||
(hat might not \214t into another section of this document, and the)
|
||||
-3.184 F 3.184(ya)-.15 G .684(re enumer)-3.184 F(-)-.2 E(ated here.)108
|
||||
148.8 Q/F2 10/Times-Bold@0 SF(What platf)108 165.6 Q
|
||||
(orms does Of\215ineIMAP run on?)-.25 E F0(It should run on most platfo\
|
||||
rms supported by Python, which are quite a fe)144 177.6 Q -.65(w.)-.25 G
|
||||
F2 .689(I'm using Mutt. Other IMAP sync pr)108 194.4 R .689(ograms r)
|
||||
-.18 F(equir)-.18 E 3.189(em)-.18 G 3.189(et)-3.189 G 3.189(ou)-3.189 G
|
||||
.689(se set maildir_trash=y)-3.189 F .688(es . Do I need to)-.1 F
|
||||
(do that with Of\215ineIMAP?)108 206.4 Q F0(No.)144 218.4 Q F2
|
||||
(Of\215ineIMAP)7.27 E F0 2.27
|
||||
(is smart enough to \214gure out message deletion without this e)4.77 F
|
||||
2.27(xtra crutch.)-.15 F -1.1(Yo)144 230.4 S(u')1.1 E
|
||||
(ll get the best results if you don')-.1 E 2.5(tu)-.18 G
|
||||
(se this setting, in f)-2.5 E(act.)-.1 E F2(Ho)108 247.2 Q 2.5(wd)-.1 G
|
||||
2.5(oIs)-2.5 G(pecify the names of my f)-2.5 E(olders?)-.25 E F0 -1.1
|
||||
(Yo)144 259.2 S 3.55(ud)1.1 G 3.55(on)-3.55 G 1.05(ot need to.)-3.55 F
|
||||
F2(Of\215ineIMAP)6.05 E F0 1.05
|
||||
(is smart enough to automatically \214gure out what folders are)3.55 F
|
||||
.679(present on the IMAP serv)144 271.2 R .679(er and synchronize them.)
|
||||
-.15 F -1.1(Yo)5.679 G 3.178(uc)1.1 G .678(an use the)-3.178 F F2 -.25
|
||||
(fo)3.178 G(lder\214lter).25 E F0(and)3.178 E F2 -.25(fo)3.178 G
|
||||
(ldertrans).25 E F0(con\214guration \214le options to request certain f\
|
||||
olders and rename them as the)144 283.2 Q 2.5(yc)-.15 G
|
||||
(ome in if you lik)-2.5 E(e.)-.1 E F2(Ho)108 300 Q 2.5(wc)-.1 G(an I pr)
|
||||
-2.5 E -2.3 -.15(ev e)-.18 H(nt certain f).15 E(olders fr)-.25 E
|
||||
(om being synced?)-.18 E F0(Use the)144 312 Q F2 -.25(fo)2.5 G
|
||||
(lder\214lter).25 E F0(option in the con\214guration \214le.)2.5 E F2
|
||||
(Ho)108 328.8 Q 2.5(wc)-.1 G(an I add or delete a f)-2.5 E(older?)-.25 E
|
||||
(Of\215ineIMAP)144 340.8 Q F0 .503(does not currently pro)3.003 F .504
|
||||
(vide this feature, b)-.15 F .504(ut if you create a ne)-.2 F 3.004(wf)
|
||||
-.25 G .504(older on the IMAP)-3.004 F(serv)144 352.8 Q(er)-.15 E 2.5
|
||||
(,i)-.4 G 2.5(tw)-2.5 G(ill be created locally automatically)-2.5 E(.)
|
||||
-.65 E F2(Ar)108 369.6 Q 2.5(et)-.18 G(her)-2.5 E 2.5(ea)-.18 G
|
||||
(ny other war)-2.5 E(nings that I should be awar)-.15 E 2.5(eo)-.18 G
|
||||
(f?)-2.5 E F0 -1(Ye)144 381.6 S(s; see the NO)1 E(TES section belo)-.4 E
|
||||
-.65(w.)-.25 G F2(What is the mailbox name r)108 398.4 Q
|
||||
(ecorder \(mbnames\) f)-.18 E(or?)-.25 E F0 1.019(The Mutt mail reader \
|
||||
is not capable of automatically determining the names of your mailbox)
|
||||
144 410.4 R(es.)-.15 E(Of)144 422.4 Q .265
|
||||
(\215ineIMAP can help it \(or man)-.25 F 2.765(yo)-.15 G .265
|
||||
(ther\) programs out be writing these names out in a format you)-2.765 F
|
||||
(specify)144 434.4 Q 5(.S)-.65 G(ee the e)-5 E(xample of)-.15 E
|
||||
(\215ineimap.conf \214le for details.)-.25 E F2(Can I synchr)108 451.2 Q
|
||||
(onize multiple accounts with Of\215ineIMAP?)-.18 E F0 3.345(Sure. Just)
|
||||
144 463.2 R .845(name them all in the accounts line in the general sect\
|
||||
ion of the con\214g \214le, and add a)3.345 F(per)144 475.2 Q
|
||||
(-account section for each one.)-.2 E F2
|
||||
(Does Of\215ineIMAP support POP?)108 492 Q F0 4.076(No. POP)144 504 R
|
||||
1.576(is not rob)4.076 F 1.576(ust enough to do a completely reliable m\
|
||||
ulti-machine synchronization lik)-.2 F(e)-.1 E(Of)144 516 Q
|
||||
(\215ineIMAP can do.)-.25 E(Of)5 E(\215ineIMAP will not support it.)-.25
|
||||
E F2(Do y)108 532.8 Q(ou support mailbox f)-.25 E
|
||||
(ormats other than Maildir?)-.25 E F0 .41(Not at present.)144 544.8 R
|
||||
.41(There is no technical reason not to; just no demand yet.)5.41 F .409
|
||||
(Maildir is a superior for)5.409 F(-)-.2 E(mat an)144 556.8 Q(yw)-.15 E
|
||||
(ay)-.1 E(.)-.65 E F2([technical] Wh)108 573.6 Q 2.5(ya)-.15 G .36 -.18
|
||||
(re y)-2.5 H(our Maildir message \214lenames so huge?)-.07 E
|
||||
(Of\215ineIMAP)144 585.6 Q F0 .958(has tw)3.458 F 3.458(or)-.1 G(ele)
|
||||
-3.458 E -.25(va)-.25 G .958(nt principles: 1\) ne).25 F -.15(ve)-.25 G
|
||||
3.459(rm).15 G .959(odifying your messages in an)-3.459 F 3.459(yw)-.15
|
||||
G .959(ay and 2\))-3.559 F .493
|
||||
(ensuring 100% reliable synchronizations.)144 597.6 R .493
|
||||
(In order to do a reliable sync,)5.493 F F2(Of\215ineIMAP)2.993 E F0
|
||||
.493(must ha)2.993 F -.15(ve)-.2 G 3.094(aw)144 609.6 S .594
|
||||
(ay to uniquely identify each e-mail.)-3.194 F .595
|
||||
(Three pieces of information are required to do this: your)5.594 F .538
|
||||
(account name, the folder name, and the message UID.)144 621.6 R .537
|
||||
(The account name can be calculated from)5.537 F 1.081
|
||||
(the path in which your messages are.)144 633.6 R 1.082
|
||||
(The folder name can usually be as well, B)6.082 F 1.082(UT some mail)
|
||||
-.1 F(clients mo)144 645.6 Q .3 -.15(ve m)-.15 H
|
||||
(essages between folders by simply mo).15 E(ving the \214le, lea)-.15 E
|
||||
(ving the name intact.)-.2 E(So,)144 662.4 Q F2(Of\215ineIMAP)3.2 E F0
|
||||
.7(must store both a UID folder ID.)3.2 F .7
|
||||
(The folder ID is necessary so)5.7 F F2(Of\215ineIMAP)3.2 E F0 .455
|
||||
(can detect a message mo)144 674.4 R -.15(ve)-.15 G 2.955(dt).15 G 2.955
|
||||
(oad)-2.955 G(if)-2.955 E .455(ferent folder)-.25 F(.)-.55 E F2
|
||||
(Of\215ineIMAP)5.455 E F0 .456(stores the UID \(U= number\) and)2.955 F
|
||||
(an md5sum of the foldername \(FMD5= number\) to f)144 686.4 Q
|
||||
(acilitate this.)-.1 E F2(What is the speed of Of\215ineIMAP')108 703.2
|
||||
Q 2.5(ss)-.37 G(ync?)-2.5 E(Of\215ineIMAP)144 715.2 Q F0 -.15(ve)2.891 G
|
||||
.391(rsions 2.0 and abo).15 F .691 -.15(ve c)-.15 H .391
|
||||
(ontain a multithreaded system.).15 F 2.891(Ag)5.391 G .39(ood w)-2.891
|
||||
F .39(ay to e)-.1 F(xperiment)-.15 E(is by setting maxsyncaccounts to 3\
|
||||
and maxconnections to 3 in each account clause.)144 727.2 Q
|
||||
(John Goerzen)72 768 Q(July 12, 2002)151.655 E(4)201.915 E EP
|
||||
%%Page: 5 5
|
||||
%%BeginPageSetup
|
||||
BP
|
||||
%%EndPageSetup
|
||||
/F0 10/Times-Roman@0 SF 111.22(OFFLINEIMAP\(1\) Of)72 48 R
|
||||
(\215ineIMAP manual)-.25 E(OFFLINEIMAP\(1\))113.72 E .381(This lets Of)
|
||||
144 84 R .381(\215ineIMAP open up multiple connections simultaneously)
|
||||
-.25 F 5.382(.T)-.65 G .382(hat will let it process mul-)-5.382 F
|
||||
(tiple folders and messages at once.)144 96 Q
|
||||
(In most cases, this will increase performance of the sync.)5 E(Don')144
|
||||
112.8 Q 3.104(ts)-.18 G .604(et the number too high.)-3.104 F .603
|
||||
(If you do that, things might actually slo)5.604 F 3.103(wd)-.25 G -.25
|
||||
(ow)-3.103 G 3.103(na).25 G 3.103(sy)-3.103 G .603(our link gets)-3.103
|
||||
F 2.632(saturated. Also,)144 124.8 R .132(too man)2.632 F 2.632(yc)-.15
|
||||
G .132(onnections can cause mail serv)-2.632 F .132(ers to ha)-.15 F
|
||||
.433 -.15(ve ex)-.2 H(cessi).15 E .433 -.15(ve l)-.25 H 2.633
|
||||
(oad. Administra-).15 F .507(tors might tak)144 136.8 R 3.007(eu)-.1 G
|
||||
.507(nkindly to this, and the serv)-3.007 F .506(er might bog do)-.15 F
|
||||
3.006(wn. There)-.25 F .506(are man)3.006 F 3.006(yv)-.15 G .506
|
||||
(ariables in the)-3.256 F(optimal setting; e)144 148.8 Q
|
||||
(xperimentation may help.)-.15 E
|
||||
(An informal benchmark yields these results for my setup:)144 165.6 Q
|
||||
(10 minutes with MacOS X Mail.app "manual cache")144 182.4 Q 2.5(5m)144
|
||||
194.4 S(inutes with GNUS agent sync)-2.5 E(20 seconds with Of)144 206.4
|
||||
Q(\215ineIMAP 1.x)-.25 E 2.5(9s)144 218.4 S(econds with Of)-2.5 E
|
||||
(\215ineIMAP 2.x)-.25 E 2.5(3s)144 230.4 S(econds with Of)-2.5 E
|
||||
(\215ineIMAP 3.x "cold start")-.25 E 2.5(2s)144 242.4 S(econds with Of)
|
||||
-2.5 E(\215ineIMAP 3.x "held connection")-.25 E/F1 10.95/Times-Bold@0 SF
|
||||
(CONFORMING T)72 259.2 Q(O)-.197 E F0 32.5<8349>108 271.2 S
|
||||
(nternet Message Access Protocol v)-32.5 E(ersion 4re)-.15 E
|
||||
(v1 \(IMAP 4re)-.25 E(v1\) as speci\214ed in RFC2060)-.25 E 32.5<834d>
|
||||
108 288 S 8.92(aildir as speci\214ed in http://www)-32.5 F(.qmail.or)
|
||||
-.65 E(g/qmail-manual-html/man5/maildir)-.18 E 8.92(.html and)-.55 F
|
||||
(http://cr)144 300 Q(.yp.to/proto/maildir)-.55 E(.html.)-.55 E 32.5
|
||||
<8353>108 316.8 S
|
||||
(tandard Python 2.2.1 as implemented on POSIX-compliant systems.)-32.5 E
|
||||
F1(NO)72 333.6 Q(TES)-.438 E/F2 10/Times-Bold@0 SF
|
||||
(DELETING LOCAL FOLDERS)87 345.6 Q(Of\215ineIMAP)108 357.6 Q F0 .533
|
||||
(does a tw)3.033 F(o-w)-.1 E .533(ay synchronization.)-.1 F .532
|
||||
(That is, if you mak)5.532 F 3.032(eac)-.1 G .532
|
||||
(hange to the mail on the serv)-3.032 F(er)-.15 E 3.032(,i)-.4 G(t)
|
||||
-3.032 E .896(will be propog)108 369.6 R .896(ated to your local cop)
|
||||
-.05 F 2.197 -.65(y, a)-.1 H .897(nd vise-v).65 F 3.397(ersa. Some)-.15
|
||||
F .897(people might think that it w)3.397 F .897(ould be wise to)-.1 F
|
||||
1.59(just delete all their local mail folders periodically)108 381.6 R
|
||||
6.59(.I)-.65 G 4.09(fy)-6.59 G 1.59(ou do this with Of)-4.09 F
|
||||
(\215ineIMAP)-.25 E 4.09(,r)-1.11 G 1.59(emember to also)-4.09 F(remo)
|
||||
108 393.6 Q 1.67 -.15(ve y)-.15 H 1.37(our local status cache \(~/.of)
|
||||
.15 F 1.37(\215ineimap by def)-.25 F 3.87(ault\). Otherwise,)-.1 F(Of)
|
||||
3.87 E 1.37(\215ineIMAP will tak)-.25 F 3.87(et)-.1 G 1.37(his as an)
|
||||
-3.87 F .416(intentional deletion of man)108 405.6 R 2.916(ym)-.15 G
|
||||
.416(essages and will interpret your action as requesting them to be de\
|
||||
leted from)-2.916 F(the serv)108 417.6 Q(er as well.)-.15 E
|
||||
(\(If you don')5 E 2.5(tu)-.18 G(nderstand this, don')-2.5 E 2.5(tw)-.18
|
||||
G(orry; you probably w)-2.6 E(on')-.1 E 2.5(te)-.18 G
|
||||
(ncounter this situation\))-2.5 E F2(MAILING LIST)87 434.4 Q F0
|
||||
(There is an Of)108 446.4 Q(\215ineIMAP mailing list a)-.25 E -.25(va)
|
||||
-.2 G(ilable.).25 E 2.447 -.8(To s)108 463.2 T .847
|
||||
(ubscribe, send the te).8 F .847
|
||||
(xt "Subscribe" in the subject of a mail to of)-.15 F
|
||||
(\215ineimap-request@complete.or)-.25 E 3.348(g. T)-.18 F(o)-.8 E
|
||||
(post, send the message to of)108 475.2 Q(\215ineimap@complete.or)-.25 E
|
||||
(g.)-.18 E F1 -.11(BU)72 492 S(GS).11 E F0
|
||||
(Should be reported to the author at the address speci\214ed belo)108
|
||||
504 Q -.65(w.)-.25 G F1(COPYRIGHT)72 520.8 Q F0(Of)108 532.8 Q
|
||||
(\215ineIMAP is Cop)-.25 E(yright \(C\) 2002 John Goerzen.)-.1 E .287
|
||||
(This program is free softw)108 549.6 R .287(are; you can redistrib)-.1
|
||||
F .286(ute it and/or modify it under the terms of the GNU General)-.2 F
|
||||
.766(Public License as published by the Free Softw)108 561.6 R .766
|
||||
(are F)-.1 F .766(oundation; either v)-.15 F .766
|
||||
(ersion 2 of the License, or \(at your)-.15 F(option\) an)108 573.6 Q
|
||||
2.5(yl)-.15 G(ater v)-2.5 E(ersion.)-.15 E .58(This program is distrib)
|
||||
108 590.4 R .579(uted in the hope that it will be useful, b)-.2 F .579
|
||||
(ut WITHOUT ANY W)-.2 F(ARRANTY)-1.2 E 3.079(;w)-.92 G(ithout)-3.079 E
|
||||
-2.15 -.25(ev e)108 602.4 T 2.729(nt).25 G .229(he implied w)-2.729 F
|
||||
.229(arranty of MERCHANT)-.1 F .229(ABILITY or FITNESS FOR A P)-.93 F
|
||||
(AR)-.92 E .23(TICULAR PURPOSE.)-.6 F(See)5.23 E
|
||||
(the GNU General Public License for more details.)108 614.4 Q -1.1(Yo)
|
||||
108 631.2 S 2.77(us)1.1 G .27(hould ha)-2.77 F .57 -.15(ve r)-.2 H(ecei)
|
||||
.15 E -.15(ve)-.25 G 2.77(dac).15 G(op)-2.77 E 2.77(yo)-.1 G 2.77(ft)
|
||||
-2.77 G .27
|
||||
(he GNU General Public License along with this program; if not, write)
|
||||
-2.77 F(to:)108 643.2 Q(Free Softw)108 660 Q(are F)-.1 E
|
||||
(oundation, Inc.)-.15 E(59 T)108 672 Q(emple Place)-.7 E(Suite 330)108
|
||||
684 Q(Boston, MA)108 696 Q(02111-1307)5 E(USA)108 708 Q(John Goerzen)72
|
||||
768 Q(July 12, 2002)151.655 E(5)201.915 E EP
|
||||
%%Page: 6 6
|
||||
%%BeginPageSetup
|
||||
BP
|
||||
%%EndPageSetup
|
||||
/F0 10/Times-Roman@0 SF 111.22(OFFLINEIMAP\(1\) Of)72 48 R
|
||||
(\215ineIMAP manual)-.25 E(OFFLINEIMAP\(1\))113.72 E/F1 10.95
|
||||
/Times-Bold@0 SF -.548(AU)72 84 S(THOR).548 E/F2 10/Times-Bold@0 SF
|
||||
(Of\215ineIMAP)108 96 Q(,)-.92 E F0 .488
|
||||
(its libraries, documentation, and all included \214les, e)2.987 F .488
|
||||
(xcept where noted, w)-.15 F .488(as written by John)-.1 F
|
||||
(Goerzen <jgoerzen@complete.or)108 108 Q(g> and cop)-.18 E
|
||||
(yright is held as stated in the COPYRIGHT section.)-.1 E(Of)108 124.8 Q
|
||||
(\215ineIMAP may be do)-.25 E(wnloaded, and information found, from its\
|
||||
homepage via either Gopher or HTTP:)-.25 E(gopher://quux.or)108 141.6 Q
|
||||
(g/1/de)-.18 E -.15(ve)-.25 G(l/of).15 E(\215ineimap)-.25 E
|
||||
(http://quux.or)108 153.6 Q(g/de)-.18 E -.15(ve)-.25 G(l/of).15 E
|
||||
(\215ineimap)-.25 E F1(SEE ALSO)72 182.4 Q F2(mutt)108 194.4 Q F0
|
||||
(\(1\),)A F2(python)2.5 E F0(\(1\).)A(John Goerzen)72 768 Q
|
||||
(July 12, 2002)151.655 E(6)201.915 E EP
|
||||
%%Trailer
|
||||
end
|
||||
%%EOF
|
462
offlineimap/head/manual.txt
Normal file
462
offlineimap/head/manual.txt
Normal file
@ -0,0 +1,462 @@
|
||||
OFFLINEIMAP(1) OfflineIMAP manual OFFLINEIMAP(1)
|
||||
|
||||
|
||||
|
||||
NAME
|
||||
OfflineIMAP - Powerful IMAP/Maildir synchronization and
|
||||
reader support
|
||||
|
||||
SYNOPSIS
|
||||
offlineimap [ -1 ] [ -a accountlist ] [ -c configfile ]
|
||||
[ -d ] [ -o ] [ -u interface ]
|
||||
|
||||
offlineimap -h | --help
|
||||
|
||||
DESCRIPTION
|
||||
OfflineIMAP is a tool to simplify your e-mail reading.
|
||||
With OfflineIMAP, you can read the same mailbox from mul-
|
||||
tiple computers. You get a current copy of your messages
|
||||
on each computer, and changes you make one place will be
|
||||
visible on all other systems. For instance, you can
|
||||
delete a message on your home computer, and it will appear
|
||||
deleted on your work computer as well. OfflineIMAP is
|
||||
also useful if you want to use a mail reader that does not
|
||||
have IMAP support, has poor IMAP support, or does not pro-
|
||||
vide disconnected operation.
|
||||
|
||||
OfflineIMAP is FAST; it synchronizes my two accounts with
|
||||
over 50 folders in 3 seconds. Other similar tools might
|
||||
take over a minute, and achieve a less-reliable result.
|
||||
Some mail readers can take over 10 minutes to do the same
|
||||
thing, and some don't even support it at all. Unlike
|
||||
other mail tools, OfflineIMAP features a multi-threaded
|
||||
synchronization algorithm that can dramatically speed up
|
||||
performance in many situations by synchronizing several
|
||||
different things simultaneously.
|
||||
|
||||
OfflineIMAP is FLEXIBLE; you can customize which folders
|
||||
are synced via regular expressions, lists, or Python
|
||||
expressions; a versatile and comprehensive configuration
|
||||
file is used to control behavior; two user interfaces are
|
||||
built-in; fine-tuning of synchronization performance is
|
||||
possible; internal or external automation is supported;
|
||||
SSL and PREAUTH tunnels are both supported; offline (or
|
||||
"unplugged") reading is supported; and esoteric IMAP fea-
|
||||
tures are supported to ensure compatibility with the
|
||||
widest variety of IMAP servers.
|
||||
|
||||
OfflineIMAP is SAFE; it uses an algorithm designed to pre-
|
||||
vent mail loss at all costs. Because of the design of
|
||||
this algorithm, even programming errors should not result
|
||||
in loss of mail. I am so confident in the algorithm that
|
||||
I use my own personal and work accounts for testing of
|
||||
OfflineIMAP pre-release, development, and beta releases.
|
||||
|
||||
METHOD OF OPERATION
|
||||
OfflineIMAP operates by maintaining a hierarchy of mail
|
||||
folders in Maildir format locally. Your own mail reader
|
||||
will read mail from this tree, and need never know that
|
||||
the mail comes from IMAP. OfflineIMAP will detect changes
|
||||
to the mail folders on your IMAP server and your own com-
|
||||
puter and bi-directionally synchronize them, copying,
|
||||
marking, and deleting messages as necessary.
|
||||
|
||||
INSTALLATION
|
||||
If you are reading this document via the "man" command, it
|
||||
is likely that you have no installation tasks to perform;
|
||||
your system administrator has already installed it. If
|
||||
you need to install it yourself, you have three options: a
|
||||
system-wide installation with Debian, system-wide instal-
|
||||
lation with other systems, and a single-user installation.
|
||||
You can download the latest version of OfflineIMAP from
|
||||
http://quux.org/devel/offlineimap/.
|
||||
|
||||
PREREQUISITES
|
||||
In order to use OfflineIMAP, you need to have these condi-
|
||||
tions satisfied:
|
||||
|
||||
o Your mail server must support IMAP. Most Internet
|
||||
Service Providers and corporate networks do, and
|
||||
most operating systems have an IMAP implementation
|
||||
readily available.
|
||||
|
||||
o You must have Python version 2.2.1 or above
|
||||
installed. If you are running on Debian GNU/Linux,
|
||||
this requirement will automatically be taken care
|
||||
of for you. If you do not have Python already,
|
||||
check with your system administrator or operating
|
||||
system vendor; or, download it from
|
||||
http://www.python.org/. If you intend to use the
|
||||
Tk interface, you must have Tkiner (python-tk)
|
||||
installed. If you intend to use the SSL interface,
|
||||
your Python must have been built with SSL support.
|
||||
|
||||
o Have a mail reader that supports the Maildir mail-
|
||||
box format. Most modern mail readers have this
|
||||
support built-in, so you can choose from a wide
|
||||
variety of mail servers. This format is also known
|
||||
as the "qmail" format, so any mail reader compati-
|
||||
ble with it will work with OfflineIMAP.
|
||||
|
||||
DEBIAN SYSTEM-WIDE INSTALLATION
|
||||
If you are tracking Debian unstable, you may install
|
||||
OfflineIMAP by simply running the following command as
|
||||
root:
|
||||
|
||||
apt-get install offlineimap
|
||||
|
||||
If you are not tracking Debian unstable, download the
|
||||
Debian .deb package from the OfflineIMAP website and then
|
||||
run dpkg -i to install the downloaded package. Then, go
|
||||
to CONFIGURATION below. You will type offlineimap to
|
||||
invoke the program.
|
||||
|
||||
OTHER SYSTEM-WIDE INSTALLATION
|
||||
Download the tar.gz version of the package from the web-
|
||||
site. Then run these commands:
|
||||
|
||||
tar -zxvf offlineimap-x.y.z.tar.gz
|
||||
cd offlineimap-x.y.z
|
||||
python2.2 setup.py
|
||||
|
||||
Some systems will need to use python instead of python2.2.
|
||||
Next, proceed to configuration. You will type offlineimap
|
||||
to invoke the program.
|
||||
|
||||
SINGLE-ACCOUNT INSTALLATION
|
||||
Download the tar.gz version of the package from the web-
|
||||
site. Then run these commands:
|
||||
|
||||
tar -zxvf offlineimap-x.y.z.tar.gz
|
||||
cd offlineimap-x.y.z
|
||||
|
||||
When you want to run OfflineIMAP, you will issue the cd
|
||||
command as above and then type ./offlineimap; there is no
|
||||
installation step necessary.
|
||||
|
||||
CONFIGURATION
|
||||
OfflineIMAP is regulated by a configuration file that is
|
||||
normally stored in ~/.offlineimaprc. OfflineIMAP ships
|
||||
with a file named offlineimap.conf that you should copy to
|
||||
that location and then edit. This file is vital to proper
|
||||
operation of the system; it sets everything you need to
|
||||
run OfflineIMAP. Full documentation for the configuration
|
||||
file is included within the sample file.
|
||||
|
||||
OPTIONS
|
||||
Most configuration is done via the configuration file.
|
||||
Nevertheless, there are a few options that you may set for
|
||||
OfflineIMAP.
|
||||
|
||||
-1 Disable all multithreading operations and use
|
||||
solely a single-thread sync. This effectively sets
|
||||
the maxsyncaccounts and all maxconnections configu-
|
||||
ration file variables to 1.
|
||||
|
||||
-a accountlist
|
||||
Overrides the accounts section in the config file.
|
||||
Lets you specify a particular account or set of
|
||||
accounts to sync without having to edit the config
|
||||
file. You might use this to exclude certain
|
||||
accounts, or to sync some accounts that you nor-
|
||||
mally prefer not to.
|
||||
|
||||
-c configfile
|
||||
Specifies a configuration file to use in lieu of
|
||||
the default, ~/.offlineimaprc.
|
||||
|
||||
-d Enables IMAP protocol stream and parsing debugging.
|
||||
This is useful if you are trying to track down a
|
||||
malfunction or figure out what is going on under
|
||||
the hood. I suggest that you use this with -1 in
|
||||
order to make the results more sensible. Note that
|
||||
this output will contain full IMAP protocol in
|
||||
plain text, including passwords, so take care to
|
||||
remove that from the debugging output before send-
|
||||
ing it to anyone else.
|
||||
|
||||
-o Run only once, ignoring any autorefresh setting in
|
||||
the config file.
|
||||
|
||||
-h, --help
|
||||
Show summary of options.
|
||||
|
||||
-u interface
|
||||
Specifies an alternative user interface module to
|
||||
use. This overrides the default specified in the
|
||||
configuration file. The UI specified with -u will
|
||||
be forced to be used, even if its isuable() method
|
||||
states that it cannot be. Use this option with
|
||||
care.
|
||||
|
||||
The pre-defined options are Tk.TKUI (a graphical
|
||||
interface) and TTY.TTYUI (a text-mode interface).
|
||||
|
||||
EXAMPLES
|
||||
Here is an example configuration for a particularly com-
|
||||
plex situation; more examples will be added later.
|
||||
|
||||
MULTIPLE ACCOUNTS WITH MUTT
|
||||
This example shows you how to set up OfflineIMAP to syn-
|
||||
chronize multiple accounts with the mutt mail reader.
|
||||
|
||||
Start by creating a directory to hold your folders:
|
||||
mkdir ~/Mail
|
||||
|
||||
In your ~/.offlineimaprc, specify this:
|
||||
accounts = Personal, Work
|
||||
|
||||
Make sure that you have both a [Personal] and a [Work]
|
||||
section, with different localfolder pathnames and enable
|
||||
[mbnames].
|
||||
|
||||
In each account section, do something like this:
|
||||
localfolders = ~/Mail/Personal
|
||||
|
||||
Add these lines to your ~/.muttrc:
|
||||
source ~/path-to-mbnames-muttrc-mailboxes
|
||||
folder-hook Personal set from="youremail@personal.com"
|
||||
folder-hook Work set from="youremail@work.com"
|
||||
set mbox_type=Maildir
|
||||
set folder=$HOME/Mail
|
||||
set spoolfile=+Personal/INBOX
|
||||
|
||||
That's it!
|
||||
|
||||
ERRORS
|
||||
If you get one of some frequently-encountered or confusing
|
||||
errors, please check this section.
|
||||
|
||||
UID validity problem for folder
|
||||
IMAP servers use a unique ID (UID) to refer to a specific
|
||||
message. This number is guaranteed to be unique to a par-
|
||||
ticular message FOREVER. No other message in the same
|
||||
folder will ever get the same UID. UIDs are an integral
|
||||
part of OfflineIMAP's synchronization scheme; they are
|
||||
used to match up messages on your computer to messages on
|
||||
the server.
|
||||
|
||||
Sometimes, the UIDs on the server might get reset. Usu-
|
||||
ally this will happen if you delete and then recreate a
|
||||
folder. When you create a folder, the server will often
|
||||
start the UID back from 1. But OfflineIMAP might still
|
||||
have the UIDs from the previous folder by the same name
|
||||
stored. OfflineIMAP will detect this condition and skip
|
||||
the folder. This is GOOD, because it prevents data loss.
|
||||
|
||||
You can fix it by removing your local folder and cache
|
||||
data. For instance, if your folders are under ~/Folders
|
||||
and the folder with the problem is INBOX, you'd type this:
|
||||
|
||||
rm -r ~/Folders/INBOX
|
||||
rm ~/.offlineimap/AccountName/INBOX
|
||||
|
||||
(replacing AccountName with the account name as specified
|
||||
in ~/.offlineimaprc)
|
||||
|
||||
Next time you run OfflineIMAP, it will re-download the
|
||||
folder with the new UIDs. Note that the procedure speci-
|
||||
fied above will lose any local changes made to the folder.
|
||||
|
||||
Some IMAP servers are broken and do not support UIDs prop-
|
||||
erly. If you continue to get this error for all your
|
||||
folders even after performing the above procedure, it is
|
||||
likely that your IMAP server falls into this category.
|
||||
OfflineIMAP is incompatible with such servers. Using
|
||||
OfflineIMAP with them will not destroy any mail, but at
|
||||
the same time, it will not actually synchronize it either.
|
||||
(OfflineIMAP will detect this condition and abort prior to
|
||||
synchronization)
|
||||
|
||||
|
||||
OTHER FREQUENTLY ASKED QUESTIONS
|
||||
There are some other FAQs that might not fit into another
|
||||
section of this document, and they are enumerated here.
|
||||
|
||||
What platforms does OfflineIMAP run on?
|
||||
It should run on most platforms supported by
|
||||
Python, which are quite a few.
|
||||
|
||||
I'm using Mutt. Other IMAP sync programs require me to use
|
||||
set maildir_trash=yes . Do I need to do that with
|
||||
OfflineIMAP?
|
||||
No. OfflineIMAP is smart enough to figure out mes-
|
||||
sage deletion without this extra crutch. You'll
|
||||
get the best results if you don't use this setting,
|
||||
in fact.
|
||||
|
||||
How do I specify the names of my folders?
|
||||
You do not need to. OfflineIMAP is smart enough to
|
||||
automatically figure out what folders are present
|
||||
on the IMAP server and synchronize them. You can
|
||||
use the folderfilter and foldertrans configuration
|
||||
file options to request certain folders and rename
|
||||
them as they come in if you like.
|
||||
|
||||
How can I prevent certain folders from being synced?
|
||||
Use the folderfilter option in the configuration
|
||||
file.
|
||||
|
||||
How can I add or delete a folder?
|
||||
OfflineIMAP does not currently provide this fea-
|
||||
ture, but if you create a new folder on the IMAP
|
||||
server, it will be created locally automatically.
|
||||
|
||||
Are there any other warnings that I should be aware of?
|
||||
Yes; see the NOTES section below.
|
||||
|
||||
What is the mailbox name recorder (mbnames) for?
|
||||
The Mutt mail reader is not capable of automati-
|
||||
cally determining the names of your mailboxes.
|
||||
OfflineIMAP can help it (or many other) programs
|
||||
out be writing these names out in a format you
|
||||
specify. See the example offlineimap.conf file for
|
||||
details.
|
||||
|
||||
Can I synchronize multiple accounts with OfflineIMAP?
|
||||
Sure. Just name them all in the accounts line in
|
||||
the general section of the config file, and add a
|
||||
per-account section for each one.
|
||||
|
||||
Does OfflineIMAP support POP?
|
||||
No. POP is not robust enough to do a completely
|
||||
reliable multi-machine synchronization like
|
||||
OfflineIMAP can do. OfflineIMAP will not support
|
||||
it.
|
||||
|
||||
Do you support mailbox formats other than Maildir?
|
||||
Not at present. There is no technical reason not
|
||||
to; just no demand yet. Maildir is a superior for-
|
||||
mat anyway.
|
||||
|
||||
[technical] Why are your Maildir message filenames so
|
||||
huge?
|
||||
OfflineIMAP has two relevant principles: 1) never
|
||||
modifying your messages in any way and 2) ensuring
|
||||
100% reliable synchronizations. In order to do a
|
||||
reliable sync, OfflineIMAP must have a way to
|
||||
uniquely identify each e-mail. Three pieces of
|
||||
information are required to do this: your account
|
||||
name, the folder name, and the message UID. The
|
||||
account name can be calculated from the path in
|
||||
which your messages are. The folder name can usu-
|
||||
ally be as well, BUT some mail clients move mes-
|
||||
sages between folders by simply moving the file,
|
||||
leaving the name intact.
|
||||
|
||||
So, OfflineIMAP must store both a UID folder ID.
|
||||
The folder ID is necessary so OfflineIMAP can
|
||||
detect a message moved to a different folder.
|
||||
OfflineIMAP stores the UID (U= number) and an
|
||||
md5sum of the foldername (FMD5= number) to facili-
|
||||
tate this.
|
||||
|
||||
What is the speed of OfflineIMAP's sync?
|
||||
OfflineIMAP versions 2.0 and above contain a multi-
|
||||
threaded system. A good way to experiment is by
|
||||
setting maxsyncaccounts to 3 and maxconnections to
|
||||
3 in each account clause.
|
||||
|
||||
This lets OfflineIMAP open up multiple connections
|
||||
simultaneously. That will let it process multiple
|
||||
folders and messages at once. In most cases, this
|
||||
will increase performance of the sync.
|
||||
|
||||
Don't set the number too high. If you do that,
|
||||
things might actually slow down as your link gets
|
||||
saturated. Also, too many connections can cause
|
||||
mail servers to have excessive load. Administra-
|
||||
tors might take unkindly to this, and the server
|
||||
might bog down. There are many variables in the
|
||||
optimal setting; experimentation may help.
|
||||
|
||||
An informal benchmark yields these results for my
|
||||
setup:
|
||||
|
||||
10 minutes with MacOS X Mail.app "manual cache"
|
||||
5 minutes with GNUS agent sync
|
||||
20 seconds with OfflineIMAP 1.x
|
||||
9 seconds with OfflineIMAP 2.x
|
||||
3 seconds with OfflineIMAP 3.x "cold start"
|
||||
2 seconds with OfflineIMAP 3.x "held connection"
|
||||
|
||||
CONFORMING TO
|
||||
o Internet Message Access Protocol version 4rev1
|
||||
(IMAP 4rev1) as specified in RFC2060
|
||||
|
||||
o Maildir as specified in http://www.qmail.org/qmail-
|
||||
manual-html/man5/maildir.html and
|
||||
http://cr.yp.to/proto/maildir.html.
|
||||
|
||||
o Standard Python 2.2.1 as implemented on POSIX-com-
|
||||
pliant systems.
|
||||
|
||||
NOTES
|
||||
DELETING LOCAL FOLDERS
|
||||
OfflineIMAP does a two-way synchronization. That is, if
|
||||
you make a change to the mail on the server, it will be
|
||||
propogated to your local copy, and vise-versa. Some peo-
|
||||
ple might think that it would be wise to just delete all
|
||||
their local mail folders periodically. If you do this
|
||||
with OfflineIMAP, remember to also remove your local sta-
|
||||
tus cache (~/.offlineimap by default). Otherwise,
|
||||
OfflineIMAP will take this as an intentional deletion of
|
||||
many messages and will interpret your action as requesting
|
||||
them to be deleted from the server as well. (If you don't
|
||||
understand this, don't worry; you probably won't encounter
|
||||
this situation)
|
||||
|
||||
MAILING LIST
|
||||
There is an OfflineIMAP mailing list available.
|
||||
|
||||
To subscribe, send the text "Subscribe" in the subject of
|
||||
a mail to offlineimap-request@complete.org. To post, send
|
||||
the message to offlineimap@complete.org.
|
||||
|
||||
BUGS
|
||||
Should be reported to the author at the address specified
|
||||
below.
|
||||
|
||||
COPYRIGHT
|
||||
OfflineIMAP is Copyright (C) 2002 John Goerzen.
|
||||
|
||||
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:
|
||||
|
||||
Free Software Foundation, Inc.
|
||||
59 Temple Place
|
||||
Suite 330
|
||||
Boston, MA 02111-1307
|
||||
USA
|
||||
|
||||
AUTHOR
|
||||
OfflineIMAP, its libraries, documentation, and all
|
||||
included files, except where noted, was written by John
|
||||
Goerzen <jgoerzen@complete.org> and copyright is held as
|
||||
stated in the COPYRIGHT section.
|
||||
|
||||
OfflineIMAP may be downloaded, and information found, from
|
||||
its homepage via either Gopher or HTTP:
|
||||
|
||||
gopher://quux.org/1/devel/offlineimap
|
||||
http://quux.org/devel/offlineimap
|
||||
|
||||
|
||||
SEE ALSO
|
||||
mutt(1), python(1).
|
||||
|
||||
|
||||
|
||||
John Goerzen July 12, 2002 OFFLINEIMAP(1)
|
564
offlineimap/head/offlineimap.1
Normal file
564
offlineimap/head/offlineimap.1
Normal file
@ -0,0 +1,564 @@
|
||||
.\" Hey, EMACS: -*- nroff -*-
|
||||
.\" First parameter, NAME, should be all caps
|
||||
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||
.\" other parameters are allowed: see man(7), man(1)
|
||||
.TH OFFLINEIMAP 1 "July 12, 2002" "John Goerzen" "OfflineIMAP manual"
|
||||
.\" Please adjust this date whenever revising the manpage.
|
||||
.\"
|
||||
.\" Some roff macros, for reference:
|
||||
.\" .nh disable hyphenation
|
||||
.\" .hy enable hyphenation
|
||||
.\" .ad l left justify
|
||||
.\" .ad b justify to both left and right margins
|
||||
.\" .nf disable filling
|
||||
.\" .fi enable filling
|
||||
.\" .br insert line break
|
||||
.\" .sp <n> insert n+1 empty lines
|
||||
.\" for manpage-specific macros, see man(7)
|
||||
.SH NAME
|
||||
OfflineIMAP \- Powerful IMAP/Maildir synchronization and reader support
|
||||
.SH SYNOPSIS
|
||||
.B offlineimap
|
||||
[
|
||||
.BI \-1
|
||||
]
|
||||
[
|
||||
.BI \-a \ accountlist
|
||||
]
|
||||
[
|
||||
.BI \-c \ configfile
|
||||
]
|
||||
.br
|
||||
[
|
||||
.BI \-d
|
||||
]
|
||||
[
|
||||
.BI \-o
|
||||
]
|
||||
[
|
||||
.BI \-u " interface"
|
||||
]
|
||||
|
||||
.\".RI [ -c \ foo ]
|
||||
.\".RI [ options ] " files" ...
|
||||
.br
|
||||
.B offlineimap
|
||||
.B \-h
|
||||
|
|
||||
.B \-\-help
|
||||
.\".RI [ options ] " files" ...
|
||||
.SH DESCRIPTION
|
||||
.B OfflineIMAP
|
||||
is a tool to simplify your e-mail reading. With
|
||||
.B OfflineIMAP,
|
||||
you can read the same mailbox from multiple computers. You get a
|
||||
current copy of your messages on each computer, and changes you make
|
||||
one place will be visible on all other systems. For instance, you can
|
||||
delete a message on your home computer, and it will appear deleted on
|
||||
your work computer as well.
|
||||
.B OfflineIMAP
|
||||
is also useful if you want to use a mail reader that does not have
|
||||
IMAP support, has poor IMAP support, or does not provide disconnected
|
||||
operation.
|
||||
.PP
|
||||
.B OfflineIMAP
|
||||
is
|
||||
.I FAST;
|
||||
it synchronizes my two accounts with over 50 folders in 3 seconds.
|
||||
Other similar tools might take over a minute, and achieve a
|
||||
less-reliable result. Some mail readers can take over 10 minutes to
|
||||
do the same thing, and some don't even support it at all. Unlike
|
||||
other mail tools,
|
||||
.B OfflineIMAP
|
||||
features a multi-threaded synchronization algorithm that can
|
||||
dramatically speed up performance in many situations by synchronizing
|
||||
several different things simultaneously.
|
||||
.PP
|
||||
.B OfflineIMAP
|
||||
is
|
||||
.I FLEXIBLE;
|
||||
you can customize which folders are synced via regular expressions, lists, or
|
||||
Python expressions; a versatile and comprehensive configuration file
|
||||
is used to control behavior; two user interfaces are built-in;
|
||||
fine-tuning of synchronization performance is possible; internal or
|
||||
external automation is supported; SSL and PREAUTH tunnels are both
|
||||
supported; offline (or "unplugged") reading is supported; and
|
||||
esoteric IMAP features are supported to ensure compatibility with the
|
||||
widest variety of IMAP servers.
|
||||
.PP
|
||||
.B OfflineIMAP
|
||||
is
|
||||
.I SAFE;
|
||||
it uses an algorithm designed to prevent mail loss at all costs.
|
||||
Because of the design of this algorithm, even programming errors
|
||||
should not result in loss of mail. I am so confident in the algorithm
|
||||
that I use my own personal and work accounts for testing of
|
||||
.B OfflineIMAP
|
||||
pre-release, development, and beta releases.
|
||||
.SS "METHOD OF OPERATION"
|
||||
.B OfflineIMAP
|
||||
operates by maintaining a hierarchy of mail folders in Maildir format
|
||||
locally. Your own mail reader will read mail from this tree, and need
|
||||
never know that the mail comes from IMAP.
|
||||
.B OfflineIMAP
|
||||
will detect changes to the mail folders on your IMAP server and your
|
||||
own computer and bi-directionally synchronize them, copying, marking,
|
||||
and deleting messages as necessary.
|
||||
.SH INSTALLATION
|
||||
If you are reading this document via the "man" command, it is likely
|
||||
that you have no installation tasks to perform; your system
|
||||
administrator has already installed it. If you need to install it
|
||||
yourself, you have three options: a system-wide installation with
|
||||
Debian, system-wide installation with other systems, and a single-user
|
||||
installation. You can download the latest version of OfflineIMAP from
|
||||
.UR http://quux.org/devel/offlineimap/
|
||||
http://quux.org/devel/offlineimap/.
|
||||
.UE
|
||||
.SS PREREQUISITES
|
||||
In order to use OfflineIMAP, you need to have these conditions
|
||||
satisfied:
|
||||
.IP \(bu
|
||||
Your mail server must support IMAP. Most Internet Service Providers
|
||||
and corporate networks do, and most operating systems have an IMAP
|
||||
implementation readily available.
|
||||
.IP \(bu
|
||||
You must have Python version 2.2.1 or above installed. If you are
|
||||
running on Debian GNU/Linux, this requirement will automatically be
|
||||
taken care of for you. If you do not have Python already, check with
|
||||
your system administrator or operating system vendor; or, download it
|
||||
from
|
||||
.UR http://www.python.org/
|
||||
http://www.python.org/.
|
||||
.UE
|
||||
If you intend to use the Tk interface, you must have Tkiner
|
||||
(python-tk) installed. If you intend to use the SSL interface, your
|
||||
Python must have been built with SSL support.
|
||||
.IP \(bu
|
||||
Have a mail reader that supports the Maildir mailbox format. Most
|
||||
modern mail readers have this support built-in, so you can choose from
|
||||
a wide variety of mail servers. This format is also known as the
|
||||
"qmail" format, so any mail reader compatible with it will work with
|
||||
OfflineIMAP.
|
||||
.SS DEBIAN SYSTEM-WIDE INSTALLATION
|
||||
If you are tracking Debian unstable, you may install
|
||||
.B OfflineIMAP
|
||||
by simply running the following command as root:
|
||||
.PP
|
||||
.B apt-get install offlineimap
|
||||
.PP
|
||||
If you are not tracking Debian unstable, download the Debian .deb
|
||||
package from the OfflineIMAP website
|
||||
and then run
|
||||
.B dpkg -i
|
||||
to install the downloaded package. Then, go to CONFIGURATION below.
|
||||
You will type
|
||||
.B offlineimap
|
||||
to invoke the program.
|
||||
.SS OTHER SYSTEM-WIDE INSTALLATION
|
||||
Download the tar.gz version of the package from the website. Then run
|
||||
these commands:
|
||||
.PP
|
||||
.B tar -zxvf offlineimap-x.y.z.tar.gz
|
||||
.br
|
||||
.B cd offlineimap-x.y.z
|
||||
.br
|
||||
.B python2.2 setup.py
|
||||
.PP
|
||||
Some systems will need to use
|
||||
.B python
|
||||
instead of
|
||||
.B python2.2.
|
||||
Next, proceed to configuration. You will type
|
||||
.B offlineimap
|
||||
to invoke the program.
|
||||
.SS SINGLE-ACCOUNT INSTALLATION
|
||||
Download the tar.gz version of the package from the website. Then run
|
||||
these commands:
|
||||
.PP
|
||||
.B tar -zxvf offlineimap-x.y.z.tar.gz
|
||||
.br
|
||||
.B cd offlineimap-x.y.z
|
||||
.PP
|
||||
When you want to run
|
||||
.B OfflineIMAP,
|
||||
you will issue the
|
||||
.B cd
|
||||
command as above and then type
|
||||
.B ./offlineimap;
|
||||
there is no installation step necessary.
|
||||
.\"##################################################
|
||||
.SH CONFIGURATION
|
||||
.B OfflineIMAP
|
||||
is regulated by a configuration file that is normally stored in
|
||||
.I ~/.offlineimaprc.
|
||||
.B OfflineIMAP
|
||||
ships with a file named
|
||||
.I offlineimap.conf
|
||||
that you should copy to that location and then edit. This file is
|
||||
vital to proper operation of the system; it sets everything you need
|
||||
to run
|
||||
.B OfflineIMAP.
|
||||
Full documentation for the configuration file is included within the
|
||||
sample file.
|
||||
.\"##################################################
|
||||
.\" TeX users may be more comfortable with the \fB<whatever>\fP and
|
||||
.\" \fI<whatever>\fP escape sequences to invode bold face and italics,
|
||||
.\" respectively.
|
||||
.\"\fBofflineimap\fP is a program that...
|
||||
.SH OPTIONS
|
||||
Most configuration is done via the configuration file. Nevertheless,
|
||||
there are a few options that you may set for
|
||||
.B OfflineIMAP.
|
||||
.TP
|
||||
.B \-1
|
||||
Disable all multithreading operations and use solely a single-thread
|
||||
sync. This effectively sets the
|
||||
.B maxsyncaccounts
|
||||
and all
|
||||
.B maxconnections
|
||||
configuration file variables to 1.
|
||||
.TP
|
||||
.BI \-a \ accountlist
|
||||
Overrides the
|
||||
.B accounts
|
||||
section in the config file. Lets you specify a particular account or
|
||||
set of accounts to sync without having to edit the config file. You
|
||||
might use this to exclude certain accounts, or to sync some accounts
|
||||
that you normally prefer not to.
|
||||
.TP
|
||||
.BI \-c \ configfile
|
||||
Specifies a configuration file to use in lieu of the default,
|
||||
.I ~/.offlineimaprc.
|
||||
.TP
|
||||
.BI \-d
|
||||
Enables IMAP protocol stream and parsing debugging. This is useful if
|
||||
you are trying to track down a malfunction or figure out what is going
|
||||
on under the hood. I suggest that you use this with
|
||||
.BI \-1
|
||||
in order to make the results more sensible. Note that this output
|
||||
will contain full IMAP protocol in plain text, including passwords, so
|
||||
take care to remove that from the debugging output before sending it
|
||||
to anyone else.
|
||||
.TP
|
||||
.B \-o
|
||||
Run only once, ignoring any autorefresh setting in the config file.
|
||||
.TP
|
||||
.B \-h, \-\-help
|
||||
Show summary of options.
|
||||
.TP
|
||||
.BI \-u \ interface
|
||||
Specifies an alternative user interface module to use. This overrides
|
||||
the default specified in the configuration file. The UI specified
|
||||
with
|
||||
.B -u
|
||||
will be forced to be used, even if its
|
||||
.B isuable()
|
||||
method states that it cannot be. Use this option with care.
|
||||
.IP
|
||||
The pre-defined options are
|
||||
.B Tk.TKUI
|
||||
(a graphical interface)
|
||||
and
|
||||
.B TTY.TTYUI
|
||||
(a text-mode interface).
|
||||
.\".TP
|
||||
.\".B \-v, \-\-version
|
||||
.\"Show version of program.
|
||||
.SH EXAMPLES
|
||||
Here is an example configuration for a particularly complex situation;
|
||||
more examples will be added later.
|
||||
.SS MULTIPLE ACCOUNTS WITH MUTT
|
||||
This example shows you how to set up
|
||||
.B OfflineIMAP
|
||||
to synchronize multiple accounts with the mutt mail reader.
|
||||
.PP
|
||||
Start by creating a directory to hold your folders:
|
||||
.br
|
||||
.B mkdir ~/Mail
|
||||
.PP
|
||||
In your
|
||||
.I ~/.offlineimaprc,
|
||||
specify this:
|
||||
.br
|
||||
.B accounts = Personal, Work
|
||||
.PP
|
||||
Make sure that you have both a
|
||||
.B [Personal]
|
||||
and a
|
||||
.B [Work]
|
||||
section, with different localfolder pathnames and enable
|
||||
.B [mbnames].
|
||||
.PP
|
||||
In each account section, do something like this:
|
||||
.br
|
||||
.B localfolders = ~/Mail/Personal
|
||||
.PP
|
||||
Add these lines to your
|
||||
.I ~/.muttrc:
|
||||
.br
|
||||
.B source ~/path-to-mbnames-muttrc-mailboxes
|
||||
.br
|
||||
.B folder-hook Personal set from="youremail@personal.com"
|
||||
.br
|
||||
.B folder-hook Work set from="youremail@work.com"
|
||||
.br
|
||||
.B set mbox_type=Maildir
|
||||
.br
|
||||
.B set folder=$HOME/Mail
|
||||
.br
|
||||
.B set spoolfile=+Personal/INBOX
|
||||
.PP
|
||||
That's it!
|
||||
.SH ERRORS
|
||||
If you get one of some frequently-encountered or confusing errors,
|
||||
please check this section.
|
||||
.SS UID validity problem for folder
|
||||
IMAP servers use a unique ID (UID) to refer to a specific message.
|
||||
This number is guaranteed to be unique to a particular message
|
||||
FOREVER. No other message in the same folder will ever get the same
|
||||
UID. UIDs are an integral part of OfflineIMAP's synchronization
|
||||
scheme; they are used to match up messages on your computer to
|
||||
messages on the server.
|
||||
.PP
|
||||
Sometimes, the UIDs on the server might get reset. Usually this will
|
||||
happen if you delete and then recreate a folder. When you create a
|
||||
folder, the server will often start the UID back from 1. But
|
||||
.B OfflineIMAP
|
||||
might still have the UIDs from the previous folder by the
|
||||
same name stored.
|
||||
.B OfflineIMAP
|
||||
will detect this condition and skip the
|
||||
folder. This is GOOD, because it prevents data loss.
|
||||
.PP
|
||||
You can fix it by removing your local folder and cache data. For
|
||||
instance, if your folders are under
|
||||
.I ~/Folders
|
||||
and the folder with the
|
||||
problem is INBOX, you'd type this:
|
||||
.PP
|
||||
.B rm -r ~/Folders/INBOX
|
||||
.br
|
||||
.B rm ~/.offlineimap/AccountName/INBOX
|
||||
.PP
|
||||
(replacing AccountName with the account name as specified in
|
||||
.I ~/.offlineimaprc)
|
||||
.PP
|
||||
Next time you run
|
||||
.B OfflineIMAP,
|
||||
it will re-download the folder with the
|
||||
new UIDs. Note that the procedure specified above will lose any local
|
||||
changes made to the folder.
|
||||
.PP
|
||||
Some IMAP servers are broken and do not support UIDs properly. If you
|
||||
continue to get this error for all your folders even after performing
|
||||
the above procedure, it is likely that your IMAP server falls into
|
||||
this category.
|
||||
.B OfflineIMAP
|
||||
is incompatible with such servers. Using
|
||||
.B OfflineIMAP
|
||||
with them will not destroy any mail, but at the same time,
|
||||
it will not actually synchronize it either. (OfflineIMAP will detect
|
||||
this condition and abort prior to synchronization)
|
||||
|
||||
.SH OTHER FREQUENTLY ASKED QUESTIONS
|
||||
There are some other FAQs that might not fit into another section of
|
||||
this document, and they are enumerated here.
|
||||
.TP
|
||||
.B What platforms does OfflineIMAP run on?
|
||||
It should run on most platforms supported by Python, which are quite a
|
||||
few.
|
||||
.TP
|
||||
.B I'm using Mutt. Other IMAP sync programs require me to use "set maildir_trash=yes". Do I need to do that with OfflineIMAP?
|
||||
No.
|
||||
.B OfflineIMAP
|
||||
is smart enough to figure out message deletion without this extra
|
||||
crutch. You'll get the best results if you don't use this setting, in
|
||||
fact.
|
||||
.TP
|
||||
.B How do I specify the names of my folders?
|
||||
You do not need to.
|
||||
.B OfflineIMAP
|
||||
is smart enough to automatically figure out what folders are present
|
||||
on the IMAP server and synchronize them. You can use the
|
||||
.B folderfilter
|
||||
and
|
||||
.B foldertrans
|
||||
configuration file options to request certain folders and rename them
|
||||
as they come in if you like.
|
||||
.TP
|
||||
.B How can I prevent certain folders from being synced?
|
||||
Use the
|
||||
.B folderfilter
|
||||
option in the configuration file.
|
||||
.TP
|
||||
.B How can I add or delete a folder?
|
||||
.B OfflineIMAP
|
||||
does not currently provide this feature, but if you create a new
|
||||
folder on the IMAP server, it will be created locally automatically.
|
||||
.TP
|
||||
.B Are there any other warnings that I should be aware of?
|
||||
Yes; see the NOTES section below.
|
||||
.TP
|
||||
.B What is the mailbox name recorder (mbnames) for?
|
||||
The Mutt mail reader is not capable of automatically determining
|
||||
the names of your mailboxes. OfflineIMAP can help it (or many other)
|
||||
programs out be writing these names out in a format you specify. See
|
||||
the example offlineimap.conf file for details.
|
||||
.TP
|
||||
.B Can I synchronize multiple accounts with OfflineIMAP?
|
||||
Sure. Just name them all in the accounts line in the general
|
||||
section of the config file, and add a per-account section for each one.
|
||||
.TP
|
||||
.B Does OfflineIMAP support POP?
|
||||
No. POP is not robust enough to do a completely reliable
|
||||
multi-machine synchronization like OfflineIMAP can do. OfflineIMAP
|
||||
will not support it.
|
||||
.TP
|
||||
.B Do you support mailbox formats other than Maildir?
|
||||
Not at present. There is no technical reason not to; just no
|
||||
demand yet. Maildir is a superior format anyway.
|
||||
.TP
|
||||
.B [technical] Why are your Maildir message filenames so huge?
|
||||
.B OfflineIMAP
|
||||
has two relevant principles: 1) never modifying your
|
||||
messages in any way and 2) ensuring 100% reliable synchronizations.
|
||||
In order to do a reliable sync,
|
||||
.B OfflineIMAP
|
||||
must have a way to
|
||||
uniquely identify each e-mail. Three pieces of information are
|
||||
required to do this: your account name, the folder name, and the
|
||||
message UID. The account name can be calculated from the path in
|
||||
which your messages are. The folder name can usually be as well, BUT
|
||||
some mail clients move messages between folders by simply moving the
|
||||
file, leaving the name intact.
|
||||
.IP
|
||||
So,
|
||||
.B OfflineIMAP
|
||||
must store both a UID folder ID. The folder ID is
|
||||
necessary so
|
||||
.B OfflineIMAP
|
||||
can detect a message moved to a different
|
||||
folder.
|
||||
.B OfflineIMAP
|
||||
stores the UID (U= number) and an md5sum of the
|
||||
foldername (FMD5= number) to facilitate this.
|
||||
.TP
|
||||
.B What is the speed of OfflineIMAP's sync?
|
||||
.B OfflineIMAP
|
||||
versions 2.0 and above contain a multithreaded system. A good way to
|
||||
experiment is by setting maxsyncaccounts to 3 and maxconnections to 3
|
||||
in each account clause.
|
||||
.IP
|
||||
This lets OfflineIMAP open up multiple connections simultaneously.
|
||||
That will let it process multiple folders and messages at once. In
|
||||
most cases, this will increase performance of the sync.
|
||||
.IP
|
||||
Don't set the number too high. If you do that, things might actually
|
||||
slow down as your link gets saturated. Also, too many connections can
|
||||
cause mail servers to have excessive load. Administrators might take
|
||||
unkindly to this, and the server might bog down. There are many
|
||||
variables in the optimal setting; experimentation may help.
|
||||
.IP
|
||||
An informal benchmark yields these results for my setup:
|
||||
.IP
|
||||
10 minutes with MacOS X Mail.app "manual cache"
|
||||
.br
|
||||
5 minutes with GNUS agent sync
|
||||
.br
|
||||
20 seconds with OfflineIMAP 1.x
|
||||
.br
|
||||
9 seconds with OfflineIMAP 2.x
|
||||
.br
|
||||
3 seconds with OfflineIMAP 3.x "cold start"
|
||||
.br
|
||||
2 seconds with OfflineIMAP 3.x "held connection"
|
||||
.SH CONFORMING TO
|
||||
.IP \(bu
|
||||
Internet Message Access Protocol version 4rev1 (IMAP 4rev1) as
|
||||
specified in RFC2060
|
||||
.IP \(bu
|
||||
Maildir as specified in
|
||||
.UR http://www.qmail.org/qmail-manual-html/man5/maildir.html
|
||||
http://www.qmail.org/qmail-manual-html/man5/maildir.html
|
||||
.UE
|
||||
and
|
||||
.UR http://cr.yp.to/proto/maildir.html
|
||||
http://cr.yp.to/proto/maildir.html.
|
||||
.UE
|
||||
.IP \(bu
|
||||
Standard Python 2.2.1 as implemented on POSIX-compliant systems.
|
||||
.SH NOTES
|
||||
.SS DELETING LOCAL FOLDERS
|
||||
.B OfflineIMAP
|
||||
does a two-way synchronization. That is, if you
|
||||
make a change to the mail on the server, it will be propogated to your
|
||||
local copy, and vise-versa. Some people might think that it would be
|
||||
wise to just delete all their local mail folders periodically. If you
|
||||
do this with OfflineIMAP, remember to also remove your local status
|
||||
cache (~/.offlineimap by default). Otherwise, OfflineIMAP will take
|
||||
this as an intentional deletion of many messages and will interpret
|
||||
your action as requesting them to be deleted from the server as well.
|
||||
(If you don't understand this, don't worry; you probably won't
|
||||
encounter this situation)
|
||||
.SS MAILING LIST
|
||||
There is an OfflineIMAP mailing list available.
|
||||
.PP
|
||||
To subscribe, send the text "Subscribe" in the subject of a mail to
|
||||
offlineimap-request@complete.org. To post, send the message to
|
||||
offlineimap@complete.org.
|
||||
.SH BUGS
|
||||
Should be reported to the author at the address specified below.
|
||||
.SH COPYRIGHT
|
||||
OfflineIMAP is Copyright (C) 2002 John Goerzen.
|
||||
.PP
|
||||
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.
|
||||
.PP
|
||||
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.
|
||||
.PP
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
.PP
|
||||
Free Software Foundation, Inc.
|
||||
.br
|
||||
59 Temple Place
|
||||
.br
|
||||
Suite 330
|
||||
.br
|
||||
Boston, MA 02111-1307
|
||||
.br
|
||||
USA
|
||||
.SH AUTHOR
|
||||
.B OfflineIMAP,
|
||||
its libraries, documentation, and all included files, except where
|
||||
noted, was written by John Goerzen <jgoerzen@complete.org> and
|
||||
copyright is held as stated in the COPYRIGHT section.
|
||||
.PP
|
||||
OfflineIMAP may be downloaded, and information found, from its
|
||||
homepage via either Gopher or HTTP:
|
||||
.PP
|
||||
.UR gopher://quux.org/1/devel/offlineimap
|
||||
gopher://quux.org/1/devel/offlineimap
|
||||
.UE
|
||||
.br
|
||||
.UR http://quux.org/devel/offlineimap
|
||||
http://quux.org/devel/offlineimap
|
||||
.UE
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR mutt (1),
|
||||
.BR python (1).
|
||||
.\".BR bar (1),
|
||||
.\".BR baz (1).
|
||||
.\".br
|
||||
.\"The programs are documented fully by
|
||||
.\".IR "The Rise and Fall of a Fooish Bar" ,
|
||||
.\"available via the Info system.
|
||||
.\".SH AUTHOR
|
||||
.\"This manual page was written by John Goerzen <jgoerzen@complete.org>,
|
||||
.\"for the Debian GNU/Linux system (but may be used by others).
|
246
offlineimap/head/offlineimap.conf
Normal file
246
offlineimap/head/offlineimap.conf
Normal file
@ -0,0 +1,246 @@
|
||||
# Sample configuration file
|
||||
# Copyright (C) 2002 John Goerzen
|
||||
# <jgoerzen@complete.org>
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
##################################################
|
||||
# General definitions
|
||||
##################################################
|
||||
|
||||
[general]
|
||||
|
||||
# This specifies where offlineimap is to store its metadata.
|
||||
# This directory will be created if it does not already exist.
|
||||
|
||||
metadata = ~/.offlineimap
|
||||
|
||||
# This variable specifies which accounts are defined. Separate them
|
||||
# with commas. Account names should be alphanumeric only.
|
||||
# You will need to specify one section per account below. You may
|
||||
# not use "general" for an account name.
|
||||
#
|
||||
|
||||
accounts = Test
|
||||
|
||||
# You can have offlineimap continue running indefinately, automatically
|
||||
# syncing your mail periodically. If you want that, specify how
|
||||
# frequently to do that (in minutes) here.
|
||||
|
||||
# autorefresh = 5
|
||||
|
||||
# Offlineimap can synchronize more the one account at a time. If you
|
||||
# want to enable this feature, set the below value to something
|
||||
# greater than 1. To force it to synchronize only one account at a
|
||||
# time, leave it at 1.
|
||||
#
|
||||
|
||||
maxsyncaccounts = 1
|
||||
|
||||
# You can specify one or more user interface modules for OfflineIMAP
|
||||
# to use. OfflineIMAP will try the first in the list, and if it
|
||||
# fails, the second, and so forth.
|
||||
#
|
||||
# The pre-defined options are:
|
||||
# Tk.TkUI -- A graphical interface
|
||||
# TTY.TTYUI -- a text-based (terminal) interface
|
||||
#
|
||||
# You can override this with a command-line option -u.
|
||||
|
||||
ui = Tk.TkUI, TTY.TTYUI
|
||||
|
||||
|
||||
##################################################
|
||||
# Mailbox name recorder
|
||||
##################################################
|
||||
|
||||
[mbnames]
|
||||
|
||||
# offlineimap can record your mailbox names in a format you specify.
|
||||
# You can define the header, each mailbox item, the separator,
|
||||
# and the footer. Here is an example for Mutt.
|
||||
# If enabled is yes, all six setting must be specified, even if they
|
||||
# are just the empty string "".
|
||||
#
|
||||
# The header, peritem, sep, and footer are all Python expressions passed
|
||||
# through eval, so you can (and must) use Python quoting.
|
||||
|
||||
enabled = no
|
||||
filename = ~/Mutt/muttrc.mailboxes
|
||||
header = "mailboxes "
|
||||
peritem = "+%(accountname)s/%(foldername)s"
|
||||
sep = " "
|
||||
footer = "\n"
|
||||
|
||||
##################################################
|
||||
# Accounts
|
||||
##################################################
|
||||
|
||||
# This is an account definition clause. You'll have one of these
|
||||
# for each account listed in general/accounts above.
|
||||
|
||||
[Test]
|
||||
|
||||
########## Basic settings
|
||||
|
||||
# Specify local repository. Your IMAP folders will be synchronized
|
||||
# to maildirs created under this path. OfflineIMAP will create the
|
||||
# maildirs for you as needed.
|
||||
|
||||
localfolders = ~/Test
|
||||
|
||||
# Specify the remote hostname.
|
||||
remotehost = examplehost
|
||||
|
||||
# Whether or not to use SSL.
|
||||
ssl = yes
|
||||
|
||||
# Specify the port. If not specified, use a default port.
|
||||
# remoteport = 993
|
||||
|
||||
# Specify the remote user name.
|
||||
remoteuser = username
|
||||
|
||||
# There are three ways to specify the password for the remote IMAP
|
||||
# server:
|
||||
#
|
||||
# 1. No password at all specified in the config file. You will
|
||||
# be prompted for the password when OfflineIMAP starts.
|
||||
#
|
||||
# 2. The remote password stored in this file with the remotepass
|
||||
# option. Example:
|
||||
#
|
||||
# remotepass = mypassword
|
||||
#
|
||||
# 3. The remote password stored as a single line in an external
|
||||
# file, which is referenced by the remotefile option. Example:
|
||||
#
|
||||
# remotepassfile = ~/Password.IMAP.Account1
|
||||
#
|
||||
# 4. With a preauth tunnel. With this method, you invoke an external
|
||||
# program that is guaranteed *NOT* to ask for a password, but rather
|
||||
# to read from stdin and write to stdout an IMAP procotol stream
|
||||
# that begins life in the PREAUTH state. When you use a tunnel,
|
||||
# you do NOT specify a user or password (if you do, they'll be
|
||||
# ignored.) Instead, you specify a preauthtunnel, as this
|
||||
# example illustrates for Courier IMAP on Debian:
|
||||
#
|
||||
# preauthtunnel = ssh -q imaphost '/usr/bin/imapd ./Maildir'
|
||||
#
|
||||
|
||||
########## Advanced settings
|
||||
|
||||
|
||||
# Some IMAP servers need a "reference" which often refers to the
|
||||
# "folder root". This is most commonly needed with UW IMAP, where
|
||||
# you might need to specify the directory in which your mail is
|
||||
# stored. Most users will not need this.
|
||||
#
|
||||
# reference = Mail
|
||||
|
||||
# You can specify a folder translator. This must be a eval-able
|
||||
# Python expression that takes a foldername arg and returns the new
|
||||
# value. I suggest a lambda. This example below will remove "INBOX." from
|
||||
# the leading edge of folders (great for Courier IMAP users)
|
||||
#
|
||||
# WARNING: you MUST construct this such that it NEVER returns
|
||||
# the same value for two folders, UNLESS the second values are
|
||||
# filtered out by folderfilter below. Failure to follow this rule
|
||||
# will result in undefined behavior
|
||||
#
|
||||
# nametrans = lambda foldername: re.sub('^INBOX.', '', foldername)
|
||||
|
||||
# You can specify which folders to sync. You can do it several ways.
|
||||
# I'll provide some examples. The folderfilter operates on the
|
||||
# *UNTRANSLATED* name, if you specify nametrans. It should return
|
||||
# true if the folder is to be included; false otherwise.
|
||||
#
|
||||
# Example 1: synchronizing only INBOX and Sent.
|
||||
#
|
||||
# folderfilter = lambda foldername: foldername in ['INBOX', 'Sent']
|
||||
#
|
||||
# Example 2: synchronizing everything except Trash.
|
||||
#
|
||||
# folderfilter = lambda foldername: foldername not in ['Trash']
|
||||
#
|
||||
# Example 3: Using a regular expression to exclude Trash and all folders
|
||||
# containing the characters "Del".
|
||||
#
|
||||
# folderfilter = lambda foldername: not re.search('(^Trash$|Del)', foldername)
|
||||
#
|
||||
# If folderfilter is not specified, ALL remote folders will be
|
||||
# synchronized.
|
||||
#
|
||||
# You can span multiple lines by indenting the others. (Use backslashes
|
||||
# at the end when required by Python syntax) For instance:
|
||||
#
|
||||
# folderfilter = lambda foldername: foldername in
|
||||
# ['INBOX', 'Sent Mail', 'Deleted Items',
|
||||
# 'Received']
|
||||
#
|
||||
# FYI, you could also include every folder with:
|
||||
#
|
||||
# folderfilter = lambda foldername: 1
|
||||
#
|
||||
# And exclude every folder with:
|
||||
#
|
||||
# folderfilter = lambda foldername: 0
|
||||
|
||||
# You can specify folderincludes to include additional folders.
|
||||
# It should return a Python list. This might be used to include a
|
||||
# folder that was excluded by your folderfilter rule, to include a
|
||||
# folder that your server does not specify with its LIST option, or
|
||||
# to include a folder that is outside your basic reference. Some examples:
|
||||
#
|
||||
# To include debian.user and debian.personal:
|
||||
#
|
||||
# folderincludes = ['debian.user', 'debian.personal']
|
||||
#
|
||||
# To include your INBOX (UW IMAPd users will find this useful if they
|
||||
# specify a reference):
|
||||
#
|
||||
# folderincludes = ['INBOX']
|
||||
#
|
||||
# To specify a long list:
|
||||
#
|
||||
# folderincludes = ['box1', 'box2', 'box3', 'box4',
|
||||
# 'box5', 'box6']
|
||||
|
||||
|
||||
# OfflineIMAP can use multiple connections to the server in order
|
||||
# to perform multiple synchronization actions simultaneously.
|
||||
# This may place a higher burden on the server. In most cases,
|
||||
# setting this value to 2 or 3 will speed up the sync, but in some
|
||||
# cases, it may slow things down. The safe answer is 1. You should
|
||||
# probably never set it to a value more than 5.
|
||||
|
||||
maxconnections = 1
|
||||
|
||||
# OfflineIMAP normally closes IMAP server connections between refreshes if
|
||||
# the global option autorefresh is specified. If you wish it to keep the
|
||||
# connection open, set this to true. If not specified, the default is
|
||||
# false. Keeping the connection open means a faster sync start the
|
||||
# next time and may use fewer server resources on connection, but uses
|
||||
# more server memory. This setting has no effect if autorefresh is not set.
|
||||
|
||||
holdconnectionopen = no
|
||||
|
||||
# If you want to have "keepalives" sent while waiting between syncs,
|
||||
# specify the amount of time IN SECONDS between keepalives here. Note that
|
||||
# sometimes more than this amount of time might pass, so don't make it
|
||||
# tight. This setting has no effect if autorefresh and holdconnectionopen
|
||||
# are not both set.
|
||||
|
||||
# keepalive = 60
|
299
offlineimap/head/offlineimap.py
Normal file
299
offlineimap/head/offlineimap.py
Normal file
@ -0,0 +1,299 @@
|
||||
#!/usr/bin/python2.2
|
||||
|
||||
# Copyright (C) 2002 John Goerzen
|
||||
# <jgoerzen@complete.org>
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
from offlineimap import imaplib, imaputil, imapserver, repository, folder, mbnames, threadutil, version
|
||||
from offlineimap.threadutil import InstanceLimitedThread, ExitNotifyThread
|
||||
import re, os, os.path, offlineimap, sys
|
||||
from ConfigParser import ConfigParser
|
||||
from threading import *
|
||||
from getopt import getopt
|
||||
|
||||
options = {}
|
||||
if '--help' in sys.argv[1:]:
|
||||
sys.stdout.write(version.cmdhelp + "\n")
|
||||
sys.exit(0)
|
||||
|
||||
for optlist in getopt(sys.argv[1:], '1oa:c:du:h')[0]:
|
||||
options[optlist[0]] = optlist[1]
|
||||
|
||||
if '-d' in options:
|
||||
imaplib.Debug = 5
|
||||
if '-h' in options:
|
||||
sys.stdout.write(version.cmdhelp)
|
||||
sys.stdout.write("\n")
|
||||
sys.exit(0)
|
||||
configfilename = os.path.expanduser("~/.offlineimaprc")
|
||||
if '-c' in options:
|
||||
configfilename = options['-c']
|
||||
|
||||
|
||||
config = ConfigParser()
|
||||
if not os.path.exists(configfilename):
|
||||
sys.stderr.write(" *** Config file %s does not exist; aborting!\n" % configfilename)
|
||||
sys.exit(1)
|
||||
|
||||
config.read(configfilename)
|
||||
|
||||
if '-u' in options:
|
||||
ui = offlineimap.ui.detector.getUImod(options['-u'])()
|
||||
else:
|
||||
ui = offlineimap.ui.detector.findUI(config)
|
||||
ui.init_banner()
|
||||
|
||||
if '-o' in options and config.has_option("general", "autorefresh"):
|
||||
config.remove_option("general", "autorefresh")
|
||||
|
||||
metadatadir = os.path.expanduser(config.get("general", "metadata"))
|
||||
if not os.path.exists(metadatadir):
|
||||
os.mkdir(metadatadir, 0700)
|
||||
|
||||
accounts = config.get("general", "accounts")
|
||||
if '-a' in options:
|
||||
accounts = options['-a']
|
||||
accounts = accounts.replace(" ", "")
|
||||
accounts = accounts.split(",")
|
||||
|
||||
server = None
|
||||
remoterepos = None
|
||||
localrepos = None
|
||||
passwords = {}
|
||||
tunnels = {}
|
||||
|
||||
if '-1' in options:
|
||||
threadutil.initInstanceLimit("ACCOUNTLIMIT", 1)
|
||||
else:
|
||||
threadutil.initInstanceLimit("ACCOUNTLIMIT",
|
||||
config.getint("general", "maxsyncaccounts"))
|
||||
|
||||
# We have to gather passwords here -- don't want to have two threads
|
||||
# asking for passwords simultaneously.
|
||||
|
||||
for account in accounts:
|
||||
if config.has_option(account, "preauthtunnel"):
|
||||
tunnels[account] = config.get(account, "preauthtunnel")
|
||||
elif config.has_option(account, "remotepass"):
|
||||
passwords[account] = config.get(account, "remotepass")
|
||||
elif config.has_option(account, "remotepassfile"):
|
||||
passfile = open(os.path.expanduser(config.get(account, "remotepassfile")))
|
||||
passwords[account] = passfile.readline().strip()
|
||||
passfile.close()
|
||||
else:
|
||||
passwords[account] = ui.getpass(account, config)
|
||||
for instancename in ["FOLDER_" + account, "MSGCOPY_" + account]:
|
||||
if '-1' in options:
|
||||
threadutil.initInstanceLimit(instancename, 1)
|
||||
else:
|
||||
threadutil.initInstanceLimit(instancename,
|
||||
config.getint(account, "maxconnections"))
|
||||
|
||||
mailboxes = []
|
||||
servers = {}
|
||||
|
||||
def syncaccount(accountname, *args):
|
||||
# We don't need an account lock because syncitall() goes through
|
||||
# each account once, then waits for all to finish.
|
||||
try:
|
||||
ui.acct(accountname)
|
||||
accountmetadata = os.path.join(metadatadir, accountname)
|
||||
if not os.path.exists(accountmetadata):
|
||||
os.mkdir(accountmetadata, 0700)
|
||||
|
||||
server = None
|
||||
if accountname in servers:
|
||||
server = servers[accountname]
|
||||
else:
|
||||
server = imapserver.ConfigedIMAPServer(config, accountname, passwords)
|
||||
servers[accountname] = server
|
||||
|
||||
remoterepos = repository.IMAP.IMAPRepository(config, accountname, server)
|
||||
|
||||
# Connect to the Maildirs.
|
||||
localrepos = repository.Maildir.MaildirRepository(os.path.expanduser(config.get(accountname, "localfolders")))
|
||||
|
||||
# Connect to the local cache.
|
||||
statusrepos = repository.LocalStatus.LocalStatusRepository(accountmetadata)
|
||||
|
||||
ui.syncfolders(remoterepos, localrepos)
|
||||
remoterepos.syncfoldersto(localrepos)
|
||||
|
||||
folderthreads = []
|
||||
for remotefolder in remoterepos.getfolders():
|
||||
thread = InstanceLimitedThread(\
|
||||
instancename = 'FOLDER_' + accountname,
|
||||
target = syncfolder,
|
||||
name = "Folder sync %s[%s]" % \
|
||||
(accountname, remotefolder.getvisiblename()),
|
||||
args = (accountname, remoterepos, remotefolder, localrepos,
|
||||
statusrepos))
|
||||
thread.setDaemon(1)
|
||||
thread.start()
|
||||
folderthreads.append(thread)
|
||||
threadutil.threadsreset(folderthreads)
|
||||
if not (config.has_option(accountname, 'holdconnectionopen') and \
|
||||
config.getboolean(accountname, 'holdconnectionopen')):
|
||||
server.close()
|
||||
finally:
|
||||
pass
|
||||
|
||||
def syncfolder(accountname, remoterepos, remotefolder, localrepos,
|
||||
statusrepos):
|
||||
# Load local folder.
|
||||
localfolder = localrepos.\
|
||||
getfolder(remotefolder.getvisiblename().\
|
||||
replace(remoterepos.getsep(), localrepos.getsep()))
|
||||
# Write the mailboxes
|
||||
mailboxes.append({'accountname': accountname,
|
||||
'foldername': localfolder.getvisiblename()})
|
||||
# Load local folder
|
||||
ui.syncingfolder(remoterepos, remotefolder, localrepos, localfolder)
|
||||
ui.loadmessagelist(localrepos, localfolder)
|
||||
localfolder.cachemessagelist()
|
||||
ui.messagelistloaded(localrepos, localfolder, len(localfolder.getmessagelist().keys()))
|
||||
|
||||
# Load status folder.
|
||||
statusfolder = statusrepos.getfolder(remotefolder.getvisiblename().\
|
||||
replace(remoterepos.getsep(),
|
||||
statusrepos.getsep()))
|
||||
statusfolder.cachemessagelist()
|
||||
|
||||
|
||||
# If either the local or the status folder has messages and
|
||||
# there is a UID validity problem, warn and abort.
|
||||
# If there are no messages, UW IMAPd loses UIDVALIDITY.
|
||||
# But we don't really need it if both local folders are empty.
|
||||
# So, in that case, save it off.
|
||||
if (len(localfolder.getmessagelist()) or \
|
||||
len(statusfolder.getmessagelist())) and \
|
||||
not localfolder.isuidvalidityok(remotefolder):
|
||||
ui.validityproblem(remotefolder)
|
||||
return
|
||||
else:
|
||||
localfolder.saveuidvalidity(remotefolder.getuidvalidity())
|
||||
|
||||
# Load remote folder.
|
||||
ui.loadmessagelist(remoterepos, remotefolder)
|
||||
remotefolder.cachemessagelist()
|
||||
ui.messagelistloaded(remoterepos, remotefolder,
|
||||
len(remotefolder.getmessagelist().keys()))
|
||||
|
||||
|
||||
#
|
||||
|
||||
if not statusfolder.isnewfolder():
|
||||
# Delete local copies of remote messages. This way,
|
||||
# if a message's flag is modified locally but it has been
|
||||
# deleted remotely, we'll delete it locally. Otherwise, we
|
||||
# try to modify a deleted message's flags! This step
|
||||
# need only be taken if a statusfolder is present; otherwise,
|
||||
# there is no action taken *to* the remote repository.
|
||||
|
||||
remotefolder.syncmessagesto_delete(localfolder, [localfolder,
|
||||
statusfolder])
|
||||
ui.syncingmessages(localrepos, localfolder, remoterepos, remotefolder)
|
||||
localfolder.syncmessagesto(statusfolder, [remotefolder, statusfolder])
|
||||
|
||||
# Synchronize remote changes.
|
||||
ui.syncingmessages(remoterepos, remotefolder, localrepos, localfolder)
|
||||
remotefolder.syncmessagesto(localfolder)
|
||||
|
||||
# Make sure the status folder is up-to-date.
|
||||
ui.syncingmessages(localrepos, localfolder, statusrepos, statusfolder)
|
||||
localfolder.syncmessagesto(statusfolder)
|
||||
statusfolder.save()
|
||||
|
||||
|
||||
def syncitall():
|
||||
global mailboxes
|
||||
mailboxes = [] # Reset.
|
||||
threads = []
|
||||
for accountname in accounts:
|
||||
thread = InstanceLimitedThread(instancename = 'ACCOUNTLIMIT',
|
||||
target = syncaccount,
|
||||
name = "Account sync %s" % accountname,
|
||||
args = (accountname,))
|
||||
thread.setDaemon(1)
|
||||
thread.start()
|
||||
threads.append(thread)
|
||||
# Wait for the threads to finish.
|
||||
threadutil.threadsreset(threads)
|
||||
mbnames.genmbnames(config, mailboxes)
|
||||
|
||||
def sync_with_timer():
|
||||
currentThread().setExitMessage('SYNC_WITH_TIMER_TERMINATE')
|
||||
syncitall()
|
||||
if config.has_option('general', 'autorefresh'):
|
||||
refreshperiod = config.getint('general', 'autorefresh') * 60
|
||||
while 1:
|
||||
# Set up keep-alives.
|
||||
kaevents = {}
|
||||
kathreads = {}
|
||||
for accountname in accounts:
|
||||
if config.has_option(accountname, 'holdconnectionopen') and \
|
||||
config.getboolean(accountname, 'holdconnectionopen') and \
|
||||
config.has_option(accountname, 'keepalive'):
|
||||
event = Event()
|
||||
kaevents[accountname] = event
|
||||
thread = ExitNotifyThread(target = servers[accountname].keepalive,
|
||||
name = "Keep alive " + accountname,
|
||||
args = (config.getint(accountname, 'keepalive'), event))
|
||||
thread.setDaemon(1)
|
||||
thread.start()
|
||||
kathreads[accountname] = thread
|
||||
if ui.sleep(refreshperiod) == 2:
|
||||
# Cancel keep-alives, but don't bother terminating threads
|
||||
for event in kaevents.values():
|
||||
event.set()
|
||||
break
|
||||
else:
|
||||
# Cancel keep-alives and wait for threads to terminate.
|
||||
for event in kaevents.values():
|
||||
event.set()
|
||||
for thread in kathreads.values():
|
||||
thread.join()
|
||||
syncitall()
|
||||
|
||||
def threadexited(thread):
|
||||
if thread.getExitCause() == 'EXCEPTION':
|
||||
if isinstance(thread.getExitException(), SystemExit):
|
||||
# Bring a SystemExit into the main thread.
|
||||
# Do not send it back to UI layer right now.
|
||||
# Maybe later send it to ui.terminate?
|
||||
raise SystemExit
|
||||
ui.threadException(thread) # Expected to terminate
|
||||
sys.exit(100) # Just in case...
|
||||
os._exit(100)
|
||||
elif thread.getExitMessage() == 'SYNC_WITH_TIMER_TERMINATE':
|
||||
ui.terminate()
|
||||
# Just in case...
|
||||
sys.exit(100)
|
||||
os._exit(100)
|
||||
else:
|
||||
ui.threadExited(thread)
|
||||
|
||||
threadutil.initexitnotify()
|
||||
t = ExitNotifyThread(target=sync_with_timer,
|
||||
name='Sync Runner')
|
||||
t.setDaemon(1)
|
||||
t.start()
|
||||
try:
|
||||
threadutil.exitnotifymonitorloop(threadexited)
|
||||
except SystemExit:
|
||||
raise
|
||||
except:
|
||||
ui.mainException() # Also expected to terminate.
|
2
offlineimap/head/offlineimap/__init__.py
Normal file
2
offlineimap/head/offlineimap/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
import ui, folder, repository, mbnames, threadutil
|
||||
|
289
offlineimap/head/offlineimap/folder/Base.py
Normal file
289
offlineimap/head/offlineimap/folder/Base.py
Normal file
@ -0,0 +1,289 @@
|
||||
# Base folder support
|
||||
# Copyright (C) 2002 John Goerzen
|
||||
# <jgoerzen@complete.org>
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
import __main__
|
||||
from threading import *
|
||||
from offlineimap import threadutil
|
||||
from offlineimap.threadutil import InstanceLimitedThread
|
||||
|
||||
class BaseFolder:
|
||||
def getname(self):
|
||||
"""Returns name"""
|
||||
return self.name
|
||||
|
||||
def suggeststhreads(self):
|
||||
"""Returns true if this folder suggests using threads for actions;
|
||||
false otherwise. Probably only IMAP will return true."""
|
||||
return 0
|
||||
|
||||
def waitforthread(self):
|
||||
"""For threading folders, waits until there is a resource available
|
||||
before firing off a thread. For all others, returns immediately."""
|
||||
pass
|
||||
|
||||
def getcopyinstancelimit(self):
|
||||
"""For threading folders, returns the instancelimitname for
|
||||
InstanceLimitedThreads."""
|
||||
raise NotImplementedException
|
||||
|
||||
def storesmessages(self):
|
||||
"""Should be true for any backend that actually saves message bodies.
|
||||
(Almost all of them). False for the LocalStatus backend. Saves
|
||||
us from having to slurp up messages just for localstatus purposes."""
|
||||
return 1
|
||||
|
||||
def getvisiblename(self):
|
||||
return self.name
|
||||
|
||||
def getroot(self):
|
||||
"""Returns the root of the folder, in a folder-specific fashion."""
|
||||
return self.root
|
||||
|
||||
def getsep(self):
|
||||
"""Returns the separator for this folder type."""
|
||||
return self.sep
|
||||
|
||||
def getfullname(self):
|
||||
if self.getroot():
|
||||
return self.getroot() + self.getsep() + self.getname()
|
||||
else:
|
||||
return self.getname()
|
||||
|
||||
def isuidvalidityok(self, remotefolder):
|
||||
raise NotImplementedException
|
||||
|
||||
def getuidvalidity(self):
|
||||
raise NotImplementedException
|
||||
|
||||
def saveuidvalidity(self, newval):
|
||||
raise NotImplementedException
|
||||
|
||||
def cachemessagelist(self):
|
||||
"""Reads the message list from disk or network and stores it in
|
||||
memory for later use. This list will not be re-read from disk or
|
||||
memory unless this function is called again."""
|
||||
raise NotImplementedException
|
||||
|
||||
def getmessagelist(self):
|
||||
"""Gets the current message list.
|
||||
You must call cachemessagelist() before calling this function!"""
|
||||
raise NotImplementedException
|
||||
|
||||
def getmessage(self, uid):
|
||||
"""Returns the content of the specified message."""
|
||||
raise NotImplementedException
|
||||
|
||||
def savemessage(self, uid, content, flags):
|
||||
"""Writes a new message, with the specified uid.
|
||||
If the uid is < 0, the backend should assign a new uid and return it.
|
||||
|
||||
If the backend cannot assign a new uid, it returns the uid passed in
|
||||
WITHOUT saving the message.
|
||||
|
||||
IMAP backend should be the only one that can assign a new uid.
|
||||
|
||||
If the uid is > 0, the backend should set the uid to this, if it can.
|
||||
If it cannot set the uid to that, it will save it anyway.
|
||||
It will return the uid assigned in any case.
|
||||
"""
|
||||
raise NotImplementedException
|
||||
|
||||
def getmessageflags(self, uid):
|
||||
"""Returns the flags for the specified message."""
|
||||
raise NotImplementedException
|
||||
|
||||
def savemessageflags(self, uid, flags):
|
||||
"""Sets the specified message's flags to the given set."""
|
||||
raise NotImplementedException
|
||||
|
||||
def addmessageflags(self, uid, flags):
|
||||
"""Adds the specified flags to the message's flag set. If a given
|
||||
flag is already present, it will not be duplicated."""
|
||||
newflags = self.getmessageflags(uid)
|
||||
for flag in flags:
|
||||
if not flag in newflags:
|
||||
newflags.append(flag)
|
||||
newflags.sort()
|
||||
self.savemessageflags(uid, newflags)
|
||||
|
||||
def addmessagesflags(self, uidlist, flags):
|
||||
for uid in uidlist:
|
||||
self.addmessageflags(uid)
|
||||
|
||||
def deletemessageflags(self, uid, flags):
|
||||
"""Removes each flag given from the message's flag set. If a given
|
||||
flag is already removed, no action will be taken for that flag."""
|
||||
newflags = self.getmessageflags(uid)
|
||||
for flag in flags:
|
||||
if flag in newflags:
|
||||
newflags.remove(flag)
|
||||
newflags.sort()
|
||||
self.savemessageflags(uid, newflags)
|
||||
|
||||
def deletemessage(self, uid):
|
||||
raise NotImplementedException
|
||||
|
||||
def deletemessages(self, uidlist):
|
||||
for uid in uidlist:
|
||||
self.deletemessage(uid)
|
||||
|
||||
def syncmessagesto_neguid(self, dest, applyto):
|
||||
"""Pass 1 of folder synchronization.
|
||||
|
||||
Look for messages in self with a negative uid. These are messages in
|
||||
Maildirs that were not added by us. Try to add them to the dests,
|
||||
and once that succeeds, get the UID, add it to the others for real,
|
||||
add it to local for real, and delete the fake one."""
|
||||
|
||||
for uid in self.getmessagelist().keys():
|
||||
if uid >= 0:
|
||||
continue
|
||||
__main__.ui.copyingmessage(uid, self, applyto)
|
||||
successobject = None
|
||||
successuid = None
|
||||
message = self.getmessage(uid)
|
||||
flags = self.getmessageflags(uid)
|
||||
for tryappend in applyto:
|
||||
successuid = tryappend.savemessage(uid, message, flags)
|
||||
if successuid > 0:
|
||||
successobject = tryappend
|
||||
break
|
||||
# Did we succeed?
|
||||
if successobject != None:
|
||||
# Copy the message to the other remote servers.
|
||||
for appendserver in [x for x in applyto if x != successobject]:
|
||||
appendserver.savemessage(successuid, message, flags)
|
||||
# Copy it to its new name on the local server and delete
|
||||
# the one without a UID.
|
||||
self.savemessage(successuid, message, flags)
|
||||
self.deletemessage(uid)
|
||||
else:
|
||||
# Did not find any server to take this message. Ignore.
|
||||
pass
|
||||
|
||||
def copymessageto(self, uid, applyto):
|
||||
# Sometimes, it could be the case that if a sync takes awhile,
|
||||
# a message might be deleted from the maildir before it can be
|
||||
# synced to the status cache. This is only a problem with
|
||||
# self.getmessage(). So, don't call self.getmessage unless
|
||||
# really needed.
|
||||
__main__.ui.copyingmessage(uid, self, applyto)
|
||||
message = ''
|
||||
# If any of the destinations actually stores the message body,
|
||||
# load it up.
|
||||
for object in applyto:
|
||||
if object.storesmessages():
|
||||
message = self.getmessage(uid)
|
||||
break
|
||||
flags = self.getmessageflags(uid)
|
||||
for object in applyto:
|
||||
newuid = object.savemessage(uid, message, flags)
|
||||
if newuid > 0 and newuid != uid:
|
||||
# Change the local uid.
|
||||
self.savemessage(newuid, message, flags)
|
||||
self.deletemessage(uid)
|
||||
uid = newuid
|
||||
|
||||
|
||||
def syncmessagesto_copy(self, dest, applyto):
|
||||
"""Pass 2 of folder synchronization.
|
||||
|
||||
Look for messages present in self but not in dest. If any, add
|
||||
them to dest."""
|
||||
threads = []
|
||||
|
||||
for uid in self.getmessagelist().keys():
|
||||
if uid < 0: # Ignore messages that pass 1 missed.
|
||||
continue
|
||||
if not uid in dest.getmessagelist():
|
||||
if self.suggeststhreads():
|
||||
self.waitforthread()
|
||||
thread = InstanceLimitedThread(\
|
||||
self.getcopyinstancelimit(),
|
||||
target = self.copymessageto,
|
||||
name = "Copy message %d from %s" % (uid,
|
||||
self.getvisiblename()),
|
||||
args = (uid, applyto))
|
||||
thread.setDaemon(1)
|
||||
thread.start()
|
||||
threads.append(thread)
|
||||
else:
|
||||
self.copymessageto(uid, applyto)
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
def syncmessagesto_delete(self, dest, applyto):
|
||||
"""Pass 3 of folder synchronization.
|
||||
|
||||
Look for message present in dest but not in self.
|
||||
If any, delete them."""
|
||||
deletelist = []
|
||||
for uid in dest.getmessagelist().keys():
|
||||
if uid < 0:
|
||||
continue
|
||||
if not uid in self.getmessagelist():
|
||||
deletelist.append(uid)
|
||||
if len(deletelist):
|
||||
__main__.ui.deletingmessages(deletelist, applyto)
|
||||
for object in applyto:
|
||||
object.deletemessages(deletelist)
|
||||
|
||||
def syncmessagesto_flags(self, dest, applyto):
|
||||
"""Pass 4 of folder synchronization.
|
||||
|
||||
Look for any flag matching issues -- set dest message to have the
|
||||
same flags that we have."""
|
||||
for uid in self.getmessagelist().keys():
|
||||
if uid < 0: # Ignore messages missed by pass 1
|
||||
continue
|
||||
selfflags = self.getmessageflags(uid)
|
||||
destflags = dest.getmessageflags(uid)
|
||||
|
||||
addflags = [x for x in selfflags if x not in destflags]
|
||||
if len(addflags):
|
||||
__main__.ui.addingflags(uid, addflags, applyto)
|
||||
for object in applyto:
|
||||
object.addmessageflags(uid, addflags)
|
||||
|
||||
delflags = [x for x in destflags if x not in selfflags]
|
||||
if len(delflags):
|
||||
__main__.ui.deletingflags(uid, delflags, applyto)
|
||||
for object in applyto:
|
||||
object.deletemessageflags(uid, delflags)
|
||||
|
||||
def syncmessagesto(self, dest, applyto = None):
|
||||
"""Syncs messages in this folder to the destination.
|
||||
If applyto is specified, it should be a list of folders (don't forget
|
||||
to include dest!) to which all write actions should be applied.
|
||||
It defaults to [dest] if not specified. It is important that
|
||||
the UID generator be listed first in applyto; that is, the other
|
||||
applyto ones should be the ones that "copy" the main action."""
|
||||
if applyto == None:
|
||||
applyto = [dest]
|
||||
|
||||
self.syncmessagesto_neguid(dest, applyto)
|
||||
self.syncmessagesto_copy(dest, applyto)
|
||||
self.syncmessagesto_delete(dest, applyto)
|
||||
|
||||
# Now, the message lists should be identical wrt the uids present.
|
||||
# (except for potential negative uids that couldn't be placed
|
||||
# anywhere)
|
||||
|
||||
self.syncmessagesto_flags(dest, applyto)
|
||||
|
||||
|
203
offlineimap/head/offlineimap/folder/IMAP.py
Normal file
203
offlineimap/head/offlineimap/folder/IMAP.py
Normal file
@ -0,0 +1,203 @@
|
||||
# IMAP folder support
|
||||
# Copyright (C) 2002 John Goerzen
|
||||
# <jgoerzen@complete.org>
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
from Base import BaseFolder
|
||||
from offlineimap import imaputil, imaplib
|
||||
import rfc822
|
||||
from StringIO import StringIO
|
||||
from copy import copy
|
||||
|
||||
class IMAPFolder(BaseFolder):
|
||||
def __init__(self, imapserver, name, visiblename, accountname):
|
||||
self.name = imaputil.dequote(name)
|
||||
self.root = imapserver.root
|
||||
self.sep = imapserver.delim
|
||||
self.imapserver = imapserver
|
||||
self.messagelist = None
|
||||
self.visiblename = visiblename
|
||||
self.accountname = accountname
|
||||
|
||||
def suggeststhreads(self):
|
||||
return 1
|
||||
|
||||
def waitforthread(self):
|
||||
self.imapserver.connectionwait()
|
||||
|
||||
def getcopyinstancelimit(self):
|
||||
return 'MSGCOPY_' + self.accountname
|
||||
|
||||
def getvisiblename(self):
|
||||
return self.visiblename
|
||||
|
||||
def getuidvalidity(self):
|
||||
imapobj = self.imapserver.acquireconnection()
|
||||
try:
|
||||
# Primes untagged_responses
|
||||
imapobj.select(self.getfullname(), readonly = 1)
|
||||
return long(imapobj.untagged_responses['UIDVALIDITY'][0])
|
||||
finally:
|
||||
self.imapserver.releaseconnection(imapobj)
|
||||
|
||||
def cachemessagelist(self):
|
||||
imapobj = self.imapserver.acquireconnection()
|
||||
self.messagelist = {}
|
||||
|
||||
try:
|
||||
# Primes untagged_responses
|
||||
imapobj.select(self.getfullname(), readonly = 1)
|
||||
maxmsgid = long(imapobj.untagged_responses['EXISTS'][0])
|
||||
if maxmsgid < 1:
|
||||
# No messages; return
|
||||
return
|
||||
|
||||
# Now, get the flags and UIDs for these.
|
||||
# We could conceivably get rid of maxmsgid and just say
|
||||
# '1:*' here.
|
||||
response = imapobj.fetch('1:%d' % maxmsgid, '(FLAGS UID)')[1]
|
||||
finally:
|
||||
self.imapserver.releaseconnection(imapobj)
|
||||
for messagestr in response:
|
||||
# Discard the message number.
|
||||
messagestr = imaputil.imapsplit(messagestr)[1]
|
||||
options = imaputil.flags2hash(messagestr)
|
||||
uid = long(options['UID'])
|
||||
flags = imaputil.flagsimap2maildir(options['FLAGS'])
|
||||
self.messagelist[uid] = {'uid': uid, 'flags': flags}
|
||||
|
||||
def getmessagelist(self):
|
||||
return self.messagelist
|
||||
|
||||
def getmessage(self, uid):
|
||||
imapobj = self.imapserver.acquireconnection()
|
||||
try:
|
||||
imapobj.select(self.getfullname(), readonly = 1)
|
||||
return imapobj.uid('fetch', '%d' % uid, '(BODY.PEEK[])')[1][0][1].replace("\r\n", "\n")
|
||||
finally:
|
||||
self.imapserver.releaseconnection(imapobj)
|
||||
|
||||
def getmessageflags(self, uid):
|
||||
return self.messagelist[uid]['flags']
|
||||
|
||||
def savemessage(self, uid, content, flags):
|
||||
imapobj = self.imapserver.acquireconnection()
|
||||
try:
|
||||
imapobj.select(self.getfullname()) # Needed for search
|
||||
|
||||
# This backend always assigns a new uid, so the uid arg is ignored.
|
||||
# In order to get the new uid, we need to save off the message ID.
|
||||
|
||||
message = rfc822.Message(StringIO(content))
|
||||
mid = imapobj._quote(message.getheader('Message-Id'))
|
||||
date = imaplib.Time2Internaldate(rfc822.parsedate(message.getheader('Date')))
|
||||
|
||||
if content.find("\r\n") == -1: # Convert line endings if not already
|
||||
content = content.replace("\n", "\r\n")
|
||||
|
||||
assert(imapobj.append(self.getfullname(),
|
||||
imaputil.flagsmaildir2imap(flags),
|
||||
date, content)[0] == 'OK')
|
||||
# Checkpoint. Let it write out the messages, etc.
|
||||
assert(imapobj.check()[0] == 'OK')
|
||||
# Now find the UID it got.
|
||||
matchinguids = imapobj.uid('search', None,
|
||||
'(HEADER Message-Id %s)' % mid)[1][0]
|
||||
matchinguids = matchinguids.split(' ')
|
||||
matchinguids.sort()
|
||||
uid = long(matchinguids[-1])
|
||||
self.messagelist[uid] = {'uid': uid, 'flags': flags}
|
||||
return uid
|
||||
finally:
|
||||
self.imapserver.releaseconnection(imapobj)
|
||||
|
||||
def savemessageflags(self, uid, flags):
|
||||
imapobj = self.imapserver.acquireconnection()
|
||||
try:
|
||||
imapobj.select(self.getfullname())
|
||||
result = imapobj.uid('store', '%d' % uid, 'FLAGS',
|
||||
imaputil.flagsmaildir2imap(flags))
|
||||
assert result[0] == 'OK', 'Error with store: ' + r[1]
|
||||
finally:
|
||||
self.imapserver.releaseconnection(imapobj)
|
||||
result = result[1][0]
|
||||
if not result:
|
||||
self.messagelist[uid]['flags'] = flags
|
||||
else:
|
||||
flags = imaputil.flags2hash(imaputil.imapsplit(result)[1])['FLAGS']
|
||||
self.messagelist[uid]['flags'] = imaputil.flagsimap2maildir(flags)
|
||||
|
||||
def addmessageflags(self, uid, flags):
|
||||
self.addmessagesflags([uid], flags)
|
||||
|
||||
def addmessagesflags(self, uidlist, flags):
|
||||
imapobj = self.imapserver.acquireconnection()
|
||||
try:
|
||||
imapobj.select(self.getfullname())
|
||||
r = imapobj.uid('store',
|
||||
imaputil.listjoin(uidlist),
|
||||
'+FLAGS',
|
||||
imaputil.flagsmaildir2imap(flags))
|
||||
assert r[0] == 'OK', 'Error with store: ' + r[1]
|
||||
r = r[1]
|
||||
finally:
|
||||
self.imapserver.releaseconnection(imapobj)
|
||||
# Some IMAP servers do not always return a result. Therefore,
|
||||
# only update the ones that it talks about, and manually fix
|
||||
# the others.
|
||||
needupdate = copy(uidlist)
|
||||
for result in r:
|
||||
if result == None:
|
||||
# Compensate for servers that don't return anything from
|
||||
# STORE.
|
||||
continue
|
||||
attributehash = imaputil.flags2hash(imaputil.imapsplit(result)[1])
|
||||
if not ('UID' in attributehash and 'FLAGS' in attributehash):
|
||||
# Compensate for servers that don't return a UID attribute.
|
||||
continue
|
||||
flags = attributehash['FLAGS']
|
||||
uid = long(attributehash['UID'])
|
||||
self.messagelist[uid]['flags'] = imaputil.flagsimap2maildir(flags)
|
||||
try:
|
||||
needupdate.remove(uid)
|
||||
except ValueError: # Let it slide if it's not in the list
|
||||
pass
|
||||
for uid in needupdate:
|
||||
for flag in flags:
|
||||
if not flag in self.messagelist[uid]['flags']:
|
||||
self.messagelist[uid]['flags'].append(flag)
|
||||
self.messagelist[uid]['flags'].sort()
|
||||
|
||||
def deletemessage(self, uid):
|
||||
self.deletemessages([uid])
|
||||
|
||||
def deletemessages(self, uidlist):
|
||||
# Weed out ones not in self.messagelist
|
||||
uidlist = [uid for uid in uidlist if uid in self.messagelist]
|
||||
if not len(uidlist):
|
||||
return
|
||||
|
||||
self.addmessagesflags(uidlist, ['T'])
|
||||
imapobj = self.imapserver.acquireconnection()
|
||||
try:
|
||||
imapobj.select(self.getfullname())
|
||||
assert(imapobj.expunge()[0] == 'OK')
|
||||
finally:
|
||||
self.imapserver.releaseconnection(imapobj)
|
||||
for uid in uidlist:
|
||||
del self.messagelist[uid]
|
||||
|
||||
|
102
offlineimap/head/offlineimap/folder/LocalStatus.py
Normal file
102
offlineimap/head/offlineimap/folder/LocalStatus.py
Normal file
@ -0,0 +1,102 @@
|
||||
# Local status cache virtual folder
|
||||
# Copyright (C) 2002 John Goerzen
|
||||
# <jgoerzen@complete.org>
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
from Base import BaseFolder
|
||||
import os
|
||||
|
||||
magicline = "OFFLINEIMAP LocalStatus CACHE DATA - DO NOT MODIFY - FORMAT 1"
|
||||
|
||||
class LocalStatusFolder(BaseFolder):
|
||||
def __init__(self, root, name):
|
||||
self.name = name
|
||||
self.root = root
|
||||
self.sep = '.'
|
||||
self.filename = os.path.join(root, name)
|
||||
self.messagelist = None
|
||||
|
||||
def storesmessages(self):
|
||||
return 0
|
||||
|
||||
def isnewfolder(self):
|
||||
return not os.path.exists(self.filename)
|
||||
|
||||
def getname(self):
|
||||
return self.name
|
||||
|
||||
def getroot(self):
|
||||
return self.root
|
||||
|
||||
def getsep(self):
|
||||
return self.sep
|
||||
|
||||
def getfullname(self):
|
||||
return self.filename
|
||||
|
||||
def cachemessagelist(self):
|
||||
if self.isnewfolder():
|
||||
self.messagelist = {}
|
||||
return
|
||||
file = open(self.filename, "rt")
|
||||
self.messagelist = {}
|
||||
line = file.readline().strip()
|
||||
assert(line == magicline)
|
||||
for line in file.xreadlines():
|
||||
line = line.strip()
|
||||
uid, flags = line.split(':')
|
||||
uid = long(uid)
|
||||
flags = [x for x in flags]
|
||||
self.messagelist[uid] = {'uid': uid, 'flags': flags}
|
||||
file.close()
|
||||
|
||||
def save(self):
|
||||
file = open(self.filename + ".tmp", "wt")
|
||||
file.write(magicline + "\n")
|
||||
for msg in self.messagelist.values():
|
||||
flags = msg['flags']
|
||||
flags.sort()
|
||||
flags = ''.join(flags)
|
||||
file.write("%s:%s\n" % (msg['uid'], flags))
|
||||
file.close()
|
||||
os.rename(self.filename + ".tmp", self.filename)
|
||||
|
||||
def getmessagelist(self):
|
||||
return self.messagelist
|
||||
|
||||
def savemessage(self, uid, content, flags):
|
||||
if uid < 0:
|
||||
# We cannot assign a uid.
|
||||
return uid
|
||||
|
||||
if uid in self.messagelist: # already have it
|
||||
self.savemessageflags(uid, flags)
|
||||
return uid
|
||||
|
||||
self.messagelist[uid] = {'uid': uid, 'flags': flags}
|
||||
return uid
|
||||
|
||||
def getmessageflags(self, uid):
|
||||
return self.messagelist[uid]['flags']
|
||||
|
||||
def savemessageflags(self, uid, flags):
|
||||
self.messagelist[uid]['flags'] = flags
|
||||
|
||||
def deletemessage(self, uid):
|
||||
if not uid in self.messagelist:
|
||||
return
|
||||
del(self.messagelist[uid])
|
||||
|
211
offlineimap/head/offlineimap/folder/Maildir.py
Normal file
211
offlineimap/head/offlineimap/folder/Maildir.py
Normal file
@ -0,0 +1,211 @@
|
||||
# Maildir folder support
|
||||
# Copyright (C) 2002 John Goerzen
|
||||
# <jgoerzen@complete.org>
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
from Base import BaseFolder
|
||||
from offlineimap import imaputil
|
||||
import os.path, os, re, time, socket, md5
|
||||
|
||||
timeseq = 0
|
||||
lasttime = long(0)
|
||||
|
||||
def gettimeseq():
|
||||
global lasttime, timeseq
|
||||
thistime = long(time.time())
|
||||
if thistime == lasttime:
|
||||
timeseq += 1
|
||||
return timeseq
|
||||
else:
|
||||
lasttime = long(time.time())
|
||||
timeseq = 0
|
||||
return timeseq
|
||||
|
||||
class MaildirFolder(BaseFolder):
|
||||
def __init__(self, root, name):
|
||||
self.name = name
|
||||
self.root = root
|
||||
self.sep = '.'
|
||||
self.uidfilename = os.path.join(self.getfullname(), "offlineimap.uidvalidity")
|
||||
self.messagelist = None
|
||||
|
||||
def getfullname(self):
|
||||
return os.path.join(self.getroot(), self.getname())
|
||||
|
||||
def getuidvalidity(self):
|
||||
if not os.path.exists(self.uidfilename):
|
||||
return None
|
||||
file = open(self.uidfilename, "rt")
|
||||
retval = long(file.readline().strip())
|
||||
file.close()
|
||||
return retval
|
||||
|
||||
def saveuidvalidity(self, newval):
|
||||
file = open(self.uidfilename, "wt")
|
||||
file.write("%d\n" % newval)
|
||||
file.close()
|
||||
|
||||
def isuidvalidityok(self, remotefolder):
|
||||
myval = self.getuidvalidity()
|
||||
if myval != None:
|
||||
return myval == remotefolder.getuidvalidity()
|
||||
else:
|
||||
self.saveuidvalidity(remotefolder.getuidvalidity())
|
||||
return 1
|
||||
|
||||
def _scanfolder(self):
|
||||
"""Cache the message list. Maildir flags are:
|
||||
R (replied)
|
||||
S (seen)
|
||||
T (trashed)
|
||||
D (draft)
|
||||
F (flagged)
|
||||
and must occur in ASCII order."""
|
||||
retval = {}
|
||||
files = []
|
||||
nouidcounter = -1 # Messages without UIDs get
|
||||
# negative UID numbers.
|
||||
for dirannex in ['new', 'cur']:
|
||||
fulldirname = os.path.join(self.getfullname(), dirannex)
|
||||
files.extend([os.path.join(fulldirname, filename) for
|
||||
filename in os.listdir(fulldirname)])
|
||||
for file in files:
|
||||
messagename = os.path.basename(file)
|
||||
foldermatch = re.search(',FMD5=([0-9a-f]{32})', messagename)
|
||||
if (not foldermatch) or \
|
||||
md5.new(self.getvisiblename()).hexdigest() \
|
||||
!= foldermatch.group(1):
|
||||
# If there is no folder MD5 specified, or if it mismatches,
|
||||
# assume it is a foreign (new) message and generate a
|
||||
# negative uid for it
|
||||
uid = nouidcounter
|
||||
nouidcounter -= 1
|
||||
else: # It comes from our folder.
|
||||
uidmatch = re.search(',U=(\d+)', messagename)
|
||||
uid = None
|
||||
if not uidmatch:
|
||||
uid = nouidcounter
|
||||
nouidcounter -= 1
|
||||
else:
|
||||
uid = long(uidmatch.group(1))
|
||||
flagmatch = re.search(':.*2,([A-Z]+)', messagename)
|
||||
flags = []
|
||||
if flagmatch:
|
||||
flags = [x for x in flagmatch.group(1)]
|
||||
flags.sort()
|
||||
if 'T' in flags:
|
||||
# Message is marked for deletion; just delete it now.
|
||||
# Otherwise, the T flag will be propogated to the IMAP
|
||||
# server, and then expunged there, and then deleted here.
|
||||
# Might as well just delete it now, to help make things
|
||||
# more robust.
|
||||
os.unlink(file)
|
||||
else:
|
||||
retval[uid] = {'uid': uid,
|
||||
'flags': flags,
|
||||
'filename': file}
|
||||
return retval
|
||||
|
||||
def cachemessagelist(self):
|
||||
self.messagelist = self._scanfolder()
|
||||
|
||||
def getmessagelist(self):
|
||||
return self.messagelist
|
||||
|
||||
def getmessage(self, uid):
|
||||
filename = self.getmessagelist()[uid]['filename']
|
||||
file = open(filename, 'rt')
|
||||
retval = file.read()
|
||||
file.close()
|
||||
return retval
|
||||
|
||||
def savemessage(self, uid, content, flags):
|
||||
if uid < 0:
|
||||
# We cannot assign a new uid.
|
||||
return uid
|
||||
if uid in self.getmessagelist():
|
||||
# We already have it.
|
||||
self.savemessageflags(uid, flags)
|
||||
return uid
|
||||
newdir = os.path.join(self.getfullname(), 'new')
|
||||
tmpdir = os.path.join(self.getfullname(), 'tmp')
|
||||
messagename = None
|
||||
attempts = 0
|
||||
while 1:
|
||||
if attempts > 15:
|
||||
raise IOError, "Couldn't write to file %s" % messagename
|
||||
messagename = '%d_%d.%d.%s,U=%d,FMD5=%s' % \
|
||||
(long(time.time()),
|
||||
gettimeseq(),
|
||||
os.getpid(),
|
||||
socket.gethostname(),
|
||||
uid,
|
||||
md5.new(self.getvisiblename()).hexdigest())
|
||||
if os.path.exists(os.path.join(tmpdir, messagename)):
|
||||
time.sleep(2)
|
||||
attempts += 1
|
||||
else:
|
||||
break
|
||||
file = open(os.path.join(tmpdir, messagename), "wt")
|
||||
file.write(content)
|
||||
file.close()
|
||||
os.link(os.path.join(tmpdir, messagename),
|
||||
os.path.join(newdir, messagename))
|
||||
os.unlink(os.path.join(tmpdir, messagename))
|
||||
self.messagelist[uid] = {'uid': uid, 'flags': [],
|
||||
'filename': os.path.join(newdir, messagename)}
|
||||
self.savemessageflags(uid, flags)
|
||||
return uid
|
||||
|
||||
def getmessageflags(self, uid):
|
||||
return self.getmessagelist()[uid]['flags']
|
||||
|
||||
def savemessageflags(self, uid, flags):
|
||||
oldfilename = self.getmessagelist()[uid]['filename']
|
||||
newpath, newname = os.path.split(oldfilename)
|
||||
infostr = ':'
|
||||
infomatch = re.search('(:.*)$', newname)
|
||||
if infomatch: # If the info string is present..
|
||||
infostr = infomatch.group(1)
|
||||
newname = newname.split(':')[0] # Strip off the info string.
|
||||
infostr = re.sub('2,[A-Z]*', '', infostr)
|
||||
flags.sort()
|
||||
infostr += '2,' + ''.join(flags)
|
||||
newname += infostr
|
||||
|
||||
newfilename = os.path.join(newpath, newname)
|
||||
if (newfilename != oldfilename):
|
||||
os.rename(oldfilename, newfilename)
|
||||
self.getmessagelist()[uid]['flags'] = flags
|
||||
self.getmessagelist()[uid]['filename'] = newfilename
|
||||
|
||||
def getmessageflags(self, uid):
|
||||
return self.getmessagelist()[uid]['flags']
|
||||
|
||||
def deletemessage(self, uid):
|
||||
if not uid in self.messagelist:
|
||||
return
|
||||
filename = self.getmessagelist()[uid]['filename']
|
||||
try:
|
||||
os.unlink(filename)
|
||||
except IOError:
|
||||
# Can't find the file -- maybe already deleted?
|
||||
newmsglist = self._scanfolder()
|
||||
if uid in newmsglist: # Nope, try new filename.
|
||||
os.unlink(newmsglist[uid]['filename'])
|
||||
# Yep -- return.
|
||||
del(self.messagelist[uid])
|
||||
|
2
offlineimap/head/offlineimap/folder/__init__.py
Normal file
2
offlineimap/head/offlineimap/folder/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
import Base, IMAP, Maildir, LocalStatus
|
||||
|
1366
offlineimap/head/offlineimap/imaplib.py
Normal file
1366
offlineimap/head/offlineimap/imaplib.py
Normal file
File diff suppressed because it is too large
Load Diff
234
offlineimap/head/offlineimap/imapserver.py
Normal file
234
offlineimap/head/offlineimap/imapserver.py
Normal file
@ -0,0 +1,234 @@
|
||||
# IMAP server support
|
||||
# Copyright (C) 2002 John Goerzen
|
||||
# <jgoerzen@complete.org>
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
from offlineimap import imaplib, imaputil, threadutil
|
||||
from threading import *
|
||||
import thread
|
||||
|
||||
class UsefulIMAPMixIn:
|
||||
def getstate(self):
|
||||
return self.state
|
||||
def getselectedfolder(self):
|
||||
if self.getstate() == 'SELECTED':
|
||||
return self.selectedfolder
|
||||
return None
|
||||
|
||||
def select(self, mailbox='INBOX', readonly=None):
|
||||
if self.getselectedfolder() == mailbox:
|
||||
self.is_readonly = readonly
|
||||
# No change; return.
|
||||
return
|
||||
result = self.__class__.__bases__[1].select(self, mailbox, readonly)
|
||||
if result[0] != 'OK':
|
||||
raise ValueError, "Error from select: %s" % str(result)
|
||||
if self.getstate() == 'SELECTED':
|
||||
self.selectedfolder = mailbox
|
||||
else:
|
||||
self.selectedfolder = None
|
||||
|
||||
class UsefulIMAP4(UsefulIMAPMixIn, imaplib.IMAP4): pass
|
||||
class UsefulIMAP4_SSL(UsefulIMAPMixIn, imaplib.IMAP4_SSL): pass
|
||||
class UsefulIMAP4_Tunnel(UsefulIMAPMixIn, imaplib.IMAP4_Tunnel): pass
|
||||
|
||||
class IMAPServer:
|
||||
def __init__(self, username = None, password = None, hostname = None,
|
||||
port = None, ssl = 1, maxconnections = 1, tunnel = None,
|
||||
reference = '""'):
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.hostname = hostname
|
||||
self.tunnel = tunnel
|
||||
self.port = port
|
||||
self.usessl = ssl
|
||||
self.delim = None
|
||||
self.root = None
|
||||
if port == None:
|
||||
if ssl:
|
||||
self.port = 993
|
||||
else:
|
||||
self.port = 143
|
||||
self.maxconnections = maxconnections
|
||||
self.availableconnections = []
|
||||
self.assignedconnections = []
|
||||
self.lastowner = {}
|
||||
self.semaphore = BoundedSemaphore(self.maxconnections)
|
||||
self.connectionlock = Lock()
|
||||
self.reference = reference
|
||||
|
||||
def getdelim(self):
|
||||
"""Returns this server's folder delimiter. Can only be called
|
||||
after one or more calls to acquireconnection."""
|
||||
return self.delim
|
||||
|
||||
def getroot(self):
|
||||
"""Returns this server's folder root. Can only be called after one
|
||||
or more calls to acquireconnection."""
|
||||
return self.root
|
||||
|
||||
|
||||
def releaseconnection(self, connection):
|
||||
self.connectionlock.acquire()
|
||||
self.assignedconnections.remove(connection)
|
||||
self.availableconnections.append(connection)
|
||||
self.connectionlock.release()
|
||||
self.semaphore.release()
|
||||
|
||||
def acquireconnection(self):
|
||||
"""Fetches a connection from the pool, making sure to create a new one
|
||||
if needed, to obey the maximum connection limits, etc.
|
||||
Opens a connection to the server and returns an appropriate
|
||||
object."""
|
||||
|
||||
self.semaphore.acquire()
|
||||
self.connectionlock.acquire()
|
||||
imapobj = None
|
||||
|
||||
if len(self.availableconnections): # One is available.
|
||||
# Try to find one that previously belonged to this thread
|
||||
# as an optimization. Start from the back since that's where
|
||||
# they're popped on.
|
||||
threadid = thread.get_ident()
|
||||
imapobj = None
|
||||
for i in range(len(self.availableconnections) - 1, -1, -1):
|
||||
tryobj = self.availableconnections[i]
|
||||
if self.lastowner[tryobj] == threadid:
|
||||
imapobj = tryobj
|
||||
del(self.availableconnections[i])
|
||||
break
|
||||
if not imapobj:
|
||||
imapobj = self.availableconnections[0]
|
||||
del(self.availableconnections[0])
|
||||
self.assignedconnections.append(imapobj)
|
||||
self.lastowner[imapobj] = thread.get_ident()
|
||||
self.connectionlock.release()
|
||||
return imapobj
|
||||
|
||||
self.connectionlock.release() # Release until need to modify data
|
||||
|
||||
# Generate a new connection.
|
||||
if self.tunnel:
|
||||
imapobj = UsefulIMAP4_Tunnel(self.tunnel)
|
||||
elif self.usessl:
|
||||
imapobj = UsefulIMAP4_SSL(self.hostname, self.port)
|
||||
else:
|
||||
imapobj = UsefulIMAP4(self.hostname, self.port)
|
||||
|
||||
if not self.tunnel:
|
||||
imapobj.login(self.username, self.password)
|
||||
|
||||
if self.delim == None:
|
||||
self.delim, self.root = \
|
||||
imaputil.imapsplit(imapobj.list(self.reference, '""')[1][0])[1:]
|
||||
self.delim = imaputil.dequote(self.delim)
|
||||
self.root = imaputil.dequote(self.root)
|
||||
|
||||
self.connectionlock.acquire()
|
||||
self.assignedconnections.append(imapobj)
|
||||
self.lastowner[imapobj] = thread.get_ident()
|
||||
self.connectionlock.release()
|
||||
return imapobj
|
||||
|
||||
def connectionwait(self):
|
||||
"""Waits until there is a connection available. Note that between
|
||||
the time that a connection becomes available and the time it is
|
||||
requested, another thread may have grabbed it. This function is
|
||||
mainly present as a way to avoid spawning thousands of threads
|
||||
to copy messages, then have them all wait for 3 available connections.
|
||||
It's OK if we have maxconnections + 1 or 2 threads, which is what
|
||||
this will help us do."""
|
||||
threadutil.semaphorewait(self.semaphore)
|
||||
|
||||
def close(self):
|
||||
# Make sure I own all the semaphores. Let the threads finish
|
||||
# their stuff. This is a blocking method.
|
||||
self.connectionlock.acquire()
|
||||
threadutil.semaphorereset(self.semaphore, self.maxconnections)
|
||||
for imapobj in self.assignedconnections + self.availableconnections:
|
||||
imapobj.logout()
|
||||
self.assignedconnections = []
|
||||
self.availableconnections = []
|
||||
self.lastowner = {}
|
||||
self.connectionlock.release()
|
||||
|
||||
def keepalive(self, timeout, event):
|
||||
"""Sends a NOOP to each connection recorded. It will wait a maximum
|
||||
of timeout seconds between doing this, and will continue to do so
|
||||
until the Event object as passed is true. This method is expected
|
||||
to be invoked in a separate thread, which should be join()'d after
|
||||
the event is set."""
|
||||
while 1:
|
||||
event.wait(timeout)
|
||||
if event.isSet():
|
||||
return
|
||||
self.connectionlock.acquire()
|
||||
numconnections = len(self.assignedconnections) + \
|
||||
len(self.availableconnections)
|
||||
self.connectionlock.release()
|
||||
threads = []
|
||||
imapobjs = []
|
||||
|
||||
for i in range(numconnections):
|
||||
imapobj = self.acquireconnection()
|
||||
imapobjs.append(imapobj)
|
||||
thr = threadutil.ExitNotifyThread(target = imapobj.noop)
|
||||
thr.setDaemon(1)
|
||||
thr.start()
|
||||
threads.append(thr)
|
||||
|
||||
for thr in threads:
|
||||
# Make sure all the commands have completed.
|
||||
thr.join()
|
||||
|
||||
for imapobj in imapobjs:
|
||||
self.releaseconnection(imapobj)
|
||||
|
||||
class ConfigedIMAPServer(IMAPServer):
|
||||
"""This class is designed for easier initialization given a ConfigParser
|
||||
object and an account name. The passwordhash is used if
|
||||
passwords for certain accounts are known. If the password for this
|
||||
account is listed, it will be obtained from there."""
|
||||
def __init__(self, config, accountname, passwordhash = {}):
|
||||
"""Initialize the object. If the account is not a tunnel,
|
||||
the password is required."""
|
||||
host = config.get(accountname, "remotehost")
|
||||
user = config.get(accountname, "remoteuser")
|
||||
port = None
|
||||
if config.has_option(accountname, "remoteport"):
|
||||
port = config.getint(accountname, "remoteport")
|
||||
ssl = config.getboolean(accountname, "ssl")
|
||||
usetunnel = config.has_option(accountname, "preauthtunnel")
|
||||
reference = '""'
|
||||
if config.has_option(accountname, "reference"):
|
||||
reference = config.get(accountname, "reference")
|
||||
server = None
|
||||
password = None
|
||||
if accountname in passwordhash:
|
||||
password = passwordhash[accountname]
|
||||
|
||||
# Connect to the remote server.
|
||||
if usetunnel:
|
||||
IMAPServer.__init__(self,
|
||||
tunnel = config.get(accountname, "preauthtunnel"),
|
||||
reference = reference,
|
||||
maxconnections = config.getint(accountname, "maxconnections"))
|
||||
else:
|
||||
if not password:
|
||||
password = config.get(accountname, 'remotepass')
|
||||
IMAPServer.__init__(self, user, password, host, port, ssl,
|
||||
config.getint(accountname, "maxconnections"),
|
||||
reference = reference)
|
139
offlineimap/head/offlineimap/imaputil.py
Normal file
139
offlineimap/head/offlineimap/imaputil.py
Normal file
@ -0,0 +1,139 @@
|
||||
# IMAP utility module
|
||||
# Copyright (C) 2002 John Goerzen
|
||||
# <jgoerzen@complete.org>
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
import re
|
||||
|
||||
def dequote(string):
|
||||
"""Takes a string which may or may not be quoted and returns it, unquoted.
|
||||
This function does NOT consider parenthised lists to be quoted.
|
||||
"""
|
||||
|
||||
if not (string[0] == '"' and string[-1] == '"'):
|
||||
return string
|
||||
string = string[1:-1] # Strip off quotes.
|
||||
string = string.replace('\\"', '"')
|
||||
string = string.replace('\\\\', '\\')
|
||||
return string
|
||||
|
||||
def flagsplit(string):
|
||||
if string[0] != '(' or string[-1] != ')':
|
||||
raise ValueError, "Passed string '%s' is not a flag list" % string
|
||||
return imapsplit(string[1:-1])
|
||||
|
||||
def options2hash(list):
|
||||
retval = {}
|
||||
counter = 0
|
||||
while (counter < len(list)):
|
||||
retval[list[counter]] = list[counter + 1]
|
||||
counter += 2
|
||||
return retval
|
||||
|
||||
def flags2hash(string):
|
||||
return options2hash(flagsplit(string))
|
||||
|
||||
def imapsplit(string):
|
||||
"""Takes a string from an IMAP conversation and returns a list containing
|
||||
its components. One example string is:
|
||||
|
||||
(\\HasNoChildren) "." "INBOX.Sent"
|
||||
|
||||
The result from parsing this will be:
|
||||
|
||||
['(\\HasNoChildren)', '"."', '"INBOX.Sent"']"""
|
||||
|
||||
workstr = string
|
||||
retval = []
|
||||
while len(workstr):
|
||||
if re.search('^\s', workstr):
|
||||
workstr = re.search('^\s(.*)$', workstr).group(1)
|
||||
elif workstr[0] == '(':
|
||||
parenlist = re.search('^(\(.*\))', workstr).group(1)
|
||||
workstr = workstr[len(parenlist):]
|
||||
retval.append(parenlist)
|
||||
elif workstr[0] == '"':
|
||||
quotelist = re.search('^("(?:[^"]|\\\\")*")', workstr).group(1)
|
||||
workstr = workstr[len(quotelist):]
|
||||
retval.append(quotelist)
|
||||
else:
|
||||
unq = re.search('^(\S+)', workstr).group(1)
|
||||
workstr = workstr[len(unq):]
|
||||
retval.append(unq)
|
||||
return retval
|
||||
|
||||
def flagsimap2maildir(string):
|
||||
flagmap = {'\\seen': 'S',
|
||||
'\\answered': 'R',
|
||||
'\\flagged': 'F',
|
||||
'\\deleted': 'T',
|
||||
'\\draft': 'D'}
|
||||
retval = []
|
||||
imapflaglist = [x.lower() for x in flagsplit(string)]
|
||||
for imapflag in imapflaglist:
|
||||
if flagmap.has_key(imapflag):
|
||||
retval.append(flagmap[imapflag])
|
||||
retval.sort()
|
||||
return retval
|
||||
|
||||
def flagsmaildir2imap(list):
|
||||
flagmap = {'S': '\\Seen',
|
||||
'R': '\\Answered',
|
||||
'F': '\\Flagged',
|
||||
'T': '\\Deleted',
|
||||
'D': '\\Draft'}
|
||||
retval = []
|
||||
for mdflag in list:
|
||||
if flagmap.has_key(mdflag):
|
||||
retval.append(flagmap[mdflag])
|
||||
retval.sort()
|
||||
return '(' + ' '.join(retval) + ')'
|
||||
|
||||
def listjoin(list):
|
||||
start = None
|
||||
end = None
|
||||
retval = []
|
||||
|
||||
def getlist(start, end):
|
||||
if start == end:
|
||||
return(str(start))
|
||||
else:
|
||||
return(str(start) + ":" + str(end))
|
||||
|
||||
|
||||
for item in list:
|
||||
if start == None:
|
||||
# First item.
|
||||
start = item
|
||||
end = item
|
||||
elif item == end + 1:
|
||||
# An addition to the list.
|
||||
end = item
|
||||
else:
|
||||
# Here on: starting a new list.
|
||||
retval.append(getlist(start, end))
|
||||
start = item
|
||||
end = item
|
||||
|
||||
if start != None:
|
||||
retval.append(getlist(start, end))
|
||||
|
||||
return ",".join(retval)
|
||||
|
||||
|
||||
|
||||
|
||||
|
34
offlineimap/head/offlineimap/mbnames.py
Normal file
34
offlineimap/head/offlineimap/mbnames.py
Normal file
@ -0,0 +1,34 @@
|
||||
# Mailbox name generator
|
||||
# Copyright (C) 2002 John Goerzen
|
||||
# <jgoerzen@complete.org>
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
import os.path
|
||||
|
||||
def genmbnames(config, boxlist):
|
||||
"""Takes a configparser object and a boxlist, which is a list of hashes
|
||||
containing 'accountname' and 'foldername' keys."""
|
||||
if not config.getboolean("mbnames", "enabled"):
|
||||
return
|
||||
file = open(os.path.expanduser(config.get("mbnames", "filename")), "wt")
|
||||
file.write(eval(config.get("mbnames", "header")))
|
||||
itemlist = [eval(config.get("mbnames", "peritem", raw=1)) % item for item in boxlist]
|
||||
file.write(eval(config.get("mbnames", "sep")).join(itemlist))
|
||||
file.write(eval(config.get("mbnames", "footer")))
|
||||
file.close()
|
||||
|
||||
|
||||
|
69
offlineimap/head/offlineimap/repository/Base.py
Normal file
69
offlineimap/head/offlineimap/repository/Base.py
Normal file
@ -0,0 +1,69 @@
|
||||
# Base repository support
|
||||
# Copyright (C) 2002 John Goerzen
|
||||
# <jgoerzen@complete.org>
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
class BaseRepository:
|
||||
def getfolders(self):
|
||||
"""Returns a list of ALL folders on this server."""
|
||||
return []
|
||||
|
||||
def getsep(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def makefolder(self, foldername):
|
||||
raise NotImplementedError
|
||||
|
||||
def deletefolder(self, foldername):
|
||||
raise NotImplementedError
|
||||
|
||||
def getfolder(self, foldername):
|
||||
raise NotImplementedError
|
||||
|
||||
def syncfoldersto(self, dest):
|
||||
"""Syncs the folders in this repository to those in dest.
|
||||
It does NOT sync the contents of those folders."""
|
||||
src = self
|
||||
srcfolders = src.getfolders()
|
||||
destfolders = dest.getfolders()
|
||||
|
||||
# Create hashes with the names, but convert the source folders
|
||||
# to the dest folder's sep.
|
||||
|
||||
srchash = {}
|
||||
for folder in srcfolders:
|
||||
srchash[folder.getvisiblename().replace(src.getsep(), dest.getsep())] = \
|
||||
folder
|
||||
desthash = {}
|
||||
for folder in destfolders:
|
||||
desthash[folder.getvisiblename()] = folder
|
||||
|
||||
#
|
||||
# Find new folders.
|
||||
#
|
||||
|
||||
for key in srchash.keys():
|
||||
if not key in desthash:
|
||||
dest.makefolder(key)
|
||||
|
||||
#
|
||||
# Find deleted folders.
|
||||
#
|
||||
|
||||
for key in desthash.keys():
|
||||
if not key in srchash:
|
||||
dest.deletefolder(key)
|
||||
|
76
offlineimap/head/offlineimap/repository/IMAP.py
Normal file
76
offlineimap/head/offlineimap/repository/IMAP.py
Normal file
@ -0,0 +1,76 @@
|
||||
# IMAP repository support
|
||||
# Copyright (C) 2002 John Goerzen
|
||||
# <jgoerzen@complete.org>
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
from Base import BaseRepository
|
||||
from offlineimap import folder, imaputil
|
||||
import re
|
||||
from threading import *
|
||||
|
||||
class IMAPRepository(BaseRepository):
|
||||
def __init__(self, config, accountname, imapserver):
|
||||
"""Initialize an IMAPRepository object. Takes an IMAPServer
|
||||
object."""
|
||||
self.imapserver = imapserver
|
||||
self.config = config
|
||||
self.accountname = accountname
|
||||
self.folders = None
|
||||
self.nametrans = lambda foldername: foldername
|
||||
self.folderfilter = lambda foldername: 1
|
||||
self.folderincludes = []
|
||||
if config.has_option(accountname, 'nametrans'):
|
||||
self.nametrans = eval(config.get(accountname, 'nametrans'))
|
||||
if config.has_option(accountname, 'folderfilter'):
|
||||
self.folderfilter = eval(config.get(accountname, 'folderfilter'))
|
||||
if config.has_option(accountname, 'folderincludes'):
|
||||
self.folderincludes = eval(config.get(accountname, 'folderincludes'))
|
||||
|
||||
def getsep(self):
|
||||
return self.imapserver.delim
|
||||
|
||||
def getfolder(self, foldername):
|
||||
return folder.IMAP.IMAPFolder(self.imapserver, foldername,
|
||||
self.nametrans(foldername),
|
||||
accountname)
|
||||
|
||||
def getfolders(self):
|
||||
if self.folders != None:
|
||||
return self.folders
|
||||
retval = []
|
||||
imapobj = self.imapserver.acquireconnection()
|
||||
try:
|
||||
listresult = imapobj.list(directory = self.imapserver.reference)[1]
|
||||
finally:
|
||||
self.imapserver.releaseconnection(imapobj)
|
||||
for string in listresult:
|
||||
flags, delim, name = imaputil.imapsplit(string)
|
||||
flaglist = [x.lower() for x in imaputil.flagsplit(flags)]
|
||||
if '\\noselect' in flaglist:
|
||||
continue
|
||||
foldername = imaputil.dequote(name)
|
||||
if not self.folderfilter(foldername):
|
||||
continue
|
||||
retval.append(folder.IMAP.IMAPFolder(self.imapserver, foldername,
|
||||
self.nametrans(foldername),
|
||||
self.accountname))
|
||||
for foldername in self.folderincludes:
|
||||
retval.append(folder.IMAP.IMAPFolder(self.imapserver, foldername,
|
||||
self.nametrans(foldername),
|
||||
self.accountname))
|
||||
retval.sort(lambda x, y: cmp(x.getvisiblename(), y.getvisiblename()))
|
||||
self.folders = retval
|
||||
return retval
|
54
offlineimap/head/offlineimap/repository/LocalStatus.py
Normal file
54
offlineimap/head/offlineimap/repository/LocalStatus.py
Normal file
@ -0,0 +1,54 @@
|
||||
# Local status cache repository support
|
||||
# Copyright (C) 2002 John Goerzen
|
||||
# <jgoerzen@complete.org>
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
from Base import BaseRepository
|
||||
from offlineimap import folder
|
||||
import os
|
||||
|
||||
class LocalStatusRepository(BaseRepository):
|
||||
def __init__(self, directory):
|
||||
self.directory = directory
|
||||
self.folders = None
|
||||
|
||||
def getsep(self):
|
||||
return '.'
|
||||
|
||||
def getfolderfilename(self, foldername):
|
||||
return os.path.join(self.directory, foldername)
|
||||
|
||||
def makefolder(self, foldername):
|
||||
# "touch" the file.
|
||||
file = open(self.getfolderfilename(foldername), "ab")
|
||||
file.close()
|
||||
# Invalidate the cache.
|
||||
self.folders = None
|
||||
|
||||
def getfolders(self):
|
||||
retval = []
|
||||
for folder in os.listdir(self.directory):
|
||||
retval.append(folder.LocalStatus.LocalStatusFolder(self.directory,
|
||||
folder))
|
||||
return retval
|
||||
|
||||
def getfolder(self, foldername):
|
||||
return folder.LocalStatus.LocalStatusFolder(self.directory, foldername)
|
||||
|
||||
|
||||
|
||||
|
||||
|
67
offlineimap/head/offlineimap/repository/Maildir.py
Normal file
67
offlineimap/head/offlineimap/repository/Maildir.py
Normal file
@ -0,0 +1,67 @@
|
||||
# Maildir repository support
|
||||
# Copyright (C) 2002 John Goerzen
|
||||
# <jgoerzen@complete.org>
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
from Base import BaseRepository
|
||||
from offlineimap import folder, imaputil
|
||||
from mailbox import Maildir
|
||||
import os
|
||||
|
||||
class MaildirRepository(BaseRepository):
|
||||
def __init__(self, root):
|
||||
"""Initialize a MaildirRepository object. Takes a path name
|
||||
to the directory holding all the Maildir directories."""
|
||||
|
||||
self.root = root
|
||||
self.folders = None
|
||||
|
||||
def getsep(self):
|
||||
return '.'
|
||||
|
||||
|
||||
|
||||
def makefolder(self, foldername):
|
||||
folderdir = os.path.join(self.root, foldername)
|
||||
os.mkdir(folderdir, 0700)
|
||||
for subdir in ['cur', 'new', 'tmp']:
|
||||
os.mkdir(os.path.join(folderdir, subdir), 0700)
|
||||
# Invalidate the cache
|
||||
self.folders = None
|
||||
|
||||
def deletefolder(self, foldername):
|
||||
print "NOT YET IMPLEMENTED: DELETE FOLDER %s" % foldername
|
||||
|
||||
def getfolder(self, foldername):
|
||||
return folder.Maildir.MaildirFolder(self.root, foldername)
|
||||
|
||||
def getfolders(self):
|
||||
if self.folders != None:
|
||||
return self.folders
|
||||
|
||||
retval = []
|
||||
for dirname in os.listdir(self.root):
|
||||
fullname = os.path.join(self.root, dirname)
|
||||
if not os.path.isdir(fullname):
|
||||
continue
|
||||
if not (os.path.isdir(os.path.join(fullname, 'cur')) and
|
||||
os.path.isdir(os.path.join(fullname, 'new')) and
|
||||
os.path.isdir(os.path.join(fullname, 'tmp'))):
|
||||
continue
|
||||
retval.append(folder.Maildir.MaildirFolder(self.root, dirname))
|
||||
self.folders = retval
|
||||
return retval
|
||||
|
1
offlineimap/head/offlineimap/repository/__init__.py
Normal file
1
offlineimap/head/offlineimap/repository/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
import IMAP, Base, Maildir, LocalStatus
|
165
offlineimap/head/offlineimap/threadutil.py
Normal file
165
offlineimap/head/offlineimap/threadutil.py
Normal file
@ -0,0 +1,165 @@
|
||||
# Copyright (C) 2002 John Goerzen
|
||||
# Thread support module
|
||||
# <jgoerzen@complete.org>
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
from threading import *
|
||||
from StringIO import StringIO
|
||||
import sys, traceback, thread
|
||||
|
||||
######################################################################
|
||||
# General utilities
|
||||
######################################################################
|
||||
|
||||
def semaphorereset(semaphore, originalstate):
|
||||
"""Wait until the semaphore gets back to its original state -- all acquired
|
||||
resources released."""
|
||||
for i in range(originalstate):
|
||||
semaphore.acquire()
|
||||
# Now release these.
|
||||
for i in range(originalstate):
|
||||
semaphore.release()
|
||||
|
||||
def semaphorewait(semaphore):
|
||||
semaphore.acquire()
|
||||
semaphore.release()
|
||||
|
||||
def threadsreset(threadlist):
|
||||
for thr in threadlist:
|
||||
thr.join()
|
||||
|
||||
######################################################################
|
||||
# Exit-notify threads
|
||||
######################################################################
|
||||
|
||||
exitcondition = Condition(Lock())
|
||||
exitthreads = []
|
||||
inited = 0
|
||||
|
||||
def initexitnotify():
|
||||
"""Initialize the exit notify system. This MUST be called from the
|
||||
SAME THREAD that will call monitorloop BEFORE it calls monitorloop.
|
||||
This SHOULD be called before the main thread starts any other
|
||||
ExitNotifyThreads, or else it may miss the ability to catch the exit
|
||||
status from them!"""
|
||||
pass
|
||||
|
||||
def exitnotifymonitorloop(callback):
|
||||
"""Enter an infinite "monitoring" loop. The argument, callback,
|
||||
defines the function to call when an ExitNotifyThread has terminated.
|
||||
That function is called with a single argument -- the ExitNotifyThread
|
||||
that has terminated. The monitor will not continue to monitor for
|
||||
other threads until the function returns, so if it intends to perform
|
||||
long calculations, it should start a new thread itself -- but NOT
|
||||
an ExitNotifyThread, or else an infinite loop may result. Furthermore,
|
||||
the monitor will hold the lock all the while the other thread is waiting.
|
||||
"""
|
||||
global exitcondition, exitthreads
|
||||
while 1: # Loop forever.
|
||||
exitcondition.acquire()
|
||||
while not len(exitthreads):
|
||||
exitcondition.wait(1)
|
||||
|
||||
while len(exitthreads):
|
||||
callback(exitthreads.pop())
|
||||
exitcondition.release()
|
||||
|
||||
class ExitNotifyThread(Thread):
|
||||
"""This class is designed to alert a "monitor" to the fact that a thread has
|
||||
exited and to provide for the ability for it to find out why."""
|
||||
def run(self):
|
||||
global exitcondition, exitthreads
|
||||
self.threadid = thread.get_ident()
|
||||
try:
|
||||
Thread.run(self)
|
||||
except:
|
||||
self.setExitCause('EXCEPTION')
|
||||
self.setExitException(sys.exc_info()[1])
|
||||
sbuf = StringIO()
|
||||
traceback.print_exc(file = sbuf)
|
||||
self.setExitStackTrace(sbuf.getvalue())
|
||||
else:
|
||||
self.setExitCause('NORMAL')
|
||||
if not hasattr(self, 'exitmessage'):
|
||||
self.setExitMessage(None)
|
||||
exitcondition.acquire()
|
||||
exitthreads.append(self)
|
||||
exitcondition.notify()
|
||||
exitcondition.release()
|
||||
|
||||
def setExitCause(self, cause):
|
||||
self.exitcause = cause
|
||||
def getExitCause(self):
|
||||
"""Returns the cause of the exit, one of:
|
||||
'EXCEPTION' -- the thread aborted because of an exception
|
||||
'NORMAL' -- normal termination."""
|
||||
return self.exitcause
|
||||
def setExitException(self, exc):
|
||||
self.exitexception = exc
|
||||
def getExitException(self):
|
||||
"""If getExitCause() is 'EXCEPTION', holds the value from
|
||||
sys.exc_info()[1] for this exception."""
|
||||
return self.exitexception
|
||||
def setExitStackTrace(self, st):
|
||||
self.exitstacktrace = st
|
||||
def getExitStackTrace(self):
|
||||
"""If getExitCause() is 'EXCEPTION', returns a string representing
|
||||
the stack trace for this exception."""
|
||||
return self.exitstacktrace
|
||||
def setExitMessage(self, msg):
|
||||
"""Sets the exit message to be fetched by a subsequent call to
|
||||
getExitMessage. This message may be any object or type except
|
||||
None."""
|
||||
self.exitmessage = msg
|
||||
def getExitMessage(self):
|
||||
"""For any exit cause, returns the message previously set by
|
||||
a call to setExitMessage(), or None if there was no such message
|
||||
set."""
|
||||
return self.exitmessage
|
||||
|
||||
|
||||
######################################################################
|
||||
# Instance-limited threads
|
||||
######################################################################
|
||||
|
||||
instancelimitedsems = {}
|
||||
instancelimitedlock = Lock()
|
||||
|
||||
def initInstanceLimit(instancename, instancemax):
|
||||
"""Initialize the instance-limited thread implementation to permit
|
||||
up to intancemax threads with the given instancename."""
|
||||
instancelimitedlock.acquire()
|
||||
if not instancelimitedsems.has_key(instancename):
|
||||
instancelimitedsems[instancename] = BoundedSemaphore(instancemax)
|
||||
instancelimitedlock.release()
|
||||
|
||||
class InstanceLimitedThread(ExitNotifyThread):
|
||||
def __init__(self, instancename, *args, **kwargs):
|
||||
self.instancename = instancename
|
||||
|
||||
apply(ExitNotifyThread.__init__, (self,) + args, kwargs)
|
||||
|
||||
def start(self):
|
||||
instancelimitedsems[self.instancename].acquire()
|
||||
ExitNotifyThread.start(self)
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
ExitNotifyThread.run(self)
|
||||
finally:
|
||||
instancelimitedsems[self.instancename].release()
|
||||
|
||||
|
82
offlineimap/head/offlineimap/ui/TTY.py
Normal file
82
offlineimap/head/offlineimap/ui/TTY.py
Normal file
@ -0,0 +1,82 @@
|
||||
# TTY UI
|
||||
# Copyright (C) 2002 John Goerzen
|
||||
# <jgoerzen@complete.org>
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
from UIBase import UIBase
|
||||
from getpass import getpass
|
||||
import select, sys
|
||||
from threading import *
|
||||
|
||||
class TTYUI(UIBase):
|
||||
def __init__(self, verbose = 0):
|
||||
self.verbose = 0
|
||||
self.iswaiting = 0
|
||||
|
||||
def _msg(s, msg):
|
||||
if (currentThread().getName() == 'MainThread'):
|
||||
print msg
|
||||
else:
|
||||
print "%s:\n %s" % (currentThread().getName(), msg)
|
||||
sys.stdout.flush()
|
||||
|
||||
def getpass(s, accountname, config):
|
||||
return getpass("%s: Enter password for %s on %s: " %
|
||||
(accountname, config.get(accountname, "remoteuser"),
|
||||
config.get(accountname, "remotehost")))
|
||||
|
||||
def syncingmessages(s, sr, sf, dr, df):
|
||||
if s.verbose:
|
||||
UIBase.syncingmessages(s, sr, sf, dr, df)
|
||||
|
||||
def loadmessagelist(s, repos, folder):
|
||||
if s.verbose:
|
||||
UIBase.syncingmessages(s, repos, folder)
|
||||
|
||||
def messagelistloaded(s, repos, folder, count):
|
||||
if s.verbose:
|
||||
UIBase.messagelistloaded(s, repos, folder, count)
|
||||
|
||||
def sleep(s, sleepsecs):
|
||||
s.iswaiting = 1
|
||||
try:
|
||||
UIBase.sleep(s, sleepsecs)
|
||||
finally:
|
||||
s.iswaiting = 0
|
||||
|
||||
def mainException(s):
|
||||
if isinstance(sys.exc_info()[1], KeyboardInterrupt) and \
|
||||
s.iswaiting:
|
||||
sys.stdout.write("Timer interrupted at user request; program terminating. \n")
|
||||
s.terminate()
|
||||
else:
|
||||
UIBase.mainException(s)
|
||||
|
||||
def sleeping(s, sleepsecs, remainingsecs):
|
||||
if remainingsecs > 0:
|
||||
sys.stdout.write("Next sync in %d:%02d (press Enter to sync now, Ctrl-C to abort) \r" % \
|
||||
(remainingsecs / 60, remainingsecs % 60))
|
||||
sys.stdout.flush()
|
||||
else:
|
||||
sys.stdout.write("Wait done, proceeding with sync.... \n")
|
||||
|
||||
if sleepsecs > 0:
|
||||
if len(select.select([sys.stdin], [], [], sleepsecs)[0]):
|
||||
sys.stdin.readline()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
298
offlineimap/head/offlineimap/ui/Tk.py
Normal file
298
offlineimap/head/offlineimap/ui/Tk.py
Normal file
@ -0,0 +1,298 @@
|
||||
# Tk UI
|
||||
# Copyright (C) 2002 John Goerzen
|
||||
# <jgoerzen@complete.org>
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
from Tkinter import *
|
||||
from threading import *
|
||||
import thread, traceback, time
|
||||
from StringIO import StringIO
|
||||
from ScrolledText import ScrolledText
|
||||
from offlineimap import threadutil, version
|
||||
from Queue import Queue
|
||||
from UIBase import UIBase
|
||||
|
||||
class PasswordDialog:
|
||||
def __init__(self, accountname, config, master=None):
|
||||
self.top = Toplevel(master)
|
||||
self.top.title(version.productname + " Password Entry")
|
||||
self.label = Label(self.top,
|
||||
text = "%s: Enter password for %s on %s: " % \
|
||||
(accountname, config.get(accountname, "remoteuser"),
|
||||
config.get(accountname, "remotehost")))
|
||||
self.label.pack()
|
||||
|
||||
self.entry = Entry(self.top, show='*')
|
||||
self.entry.bind("<Return>", self.ok)
|
||||
self.entry.pack()
|
||||
self.entry.focus_force()
|
||||
|
||||
self.button = Button(self.top, text = "OK", command=self.ok)
|
||||
self.button.pack()
|
||||
|
||||
self.entry.focus_force()
|
||||
self.top.wait_window(self.label)
|
||||
|
||||
def ok(self, args = None):
|
||||
self.password = self.entry.get()
|
||||
self.top.destroy()
|
||||
|
||||
def getpassword(self):
|
||||
return self.password
|
||||
|
||||
class TextOKDialog:
|
||||
def __init__(self, title, message, blocking = 1, master = None):
|
||||
if not master:
|
||||
self.top = Tk()
|
||||
else:
|
||||
self.top = Toplevel(master)
|
||||
self.top.title(title)
|
||||
self.text = ScrolledText(self.top, font = "Courier 10")
|
||||
self.text.pack()
|
||||
self.text.insert(END, message)
|
||||
self.text['state'] = DISABLED
|
||||
self.button = Button(self.top, text = "OK", command=self.ok)
|
||||
self.button.pack()
|
||||
|
||||
if blocking:
|
||||
self.top.wait_window(self.button)
|
||||
|
||||
def ok(self):
|
||||
self.top.destroy()
|
||||
|
||||
|
||||
|
||||
class ThreadFrame(Frame):
|
||||
def __init__(self, master=None):
|
||||
self.threadextraframe = None
|
||||
self.thread = currentThread()
|
||||
self.threadid = thread.get_ident()
|
||||
Frame.__init__(self, master, relief = RIDGE, borderwidth = 2)
|
||||
self.pack(fill = 'x')
|
||||
self.threadlabel = Label(self, foreground = '#FF0000',
|
||||
text ="Thread %d (%s)" % (self.threadid,
|
||||
self.thread.getName()))
|
||||
self.threadlabel.pack()
|
||||
self.setthread(currentThread())
|
||||
|
||||
self.account = "Unknown"
|
||||
self.mailbox = "Unknown"
|
||||
self.loclabel = Label(self,
|
||||
text = "Account/mailbox information unknown")
|
||||
#self.loclabel.pack()
|
||||
|
||||
self.updateloclabel()
|
||||
|
||||
self.message = Label(self, text="Messages will appear here.\n",
|
||||
foreground = '#0000FF')
|
||||
self.message.pack(fill = 'x')
|
||||
|
||||
def setthread(self, newthread):
|
||||
if newthread:
|
||||
self.threadlabel['text'] = newthread.getName()
|
||||
else:
|
||||
self.threadlabel['text'] = "No thread"
|
||||
self.destroythreadextraframe()
|
||||
|
||||
def destroythreadextraframe(self):
|
||||
if self.threadextraframe:
|
||||
self.threadextraframe.destroy()
|
||||
self.threadextraframe = None
|
||||
|
||||
def getthreadextraframe(self):
|
||||
if self.threadextraframe:
|
||||
return self.threadextraframe
|
||||
self.threadextraframe = Frame(self)
|
||||
self.threadextraframe.pack(fill = 'x')
|
||||
return self.threadextraframe
|
||||
|
||||
def setaccount(self, account):
|
||||
self.account = account
|
||||
self.mailbox = "Unknown"
|
||||
self.updateloclabel()
|
||||
|
||||
def setmailbox(self, mailbox):
|
||||
self.mailbox = mailbox
|
||||
self.updateloclabel()
|
||||
|
||||
def updateloclabel(self):
|
||||
self.loclabel['text'] = "Processing %s: %s" % (self.account,
|
||||
self.mailbox)
|
||||
|
||||
def appendmessage(self, newtext):
|
||||
self.message['text'] += "\n" + newtext
|
||||
|
||||
def setmessage(self, newtext):
|
||||
self.message['text'] = newtext
|
||||
|
||||
|
||||
class TkUI(UIBase):
|
||||
def __init__(self, verbose = 0):
|
||||
self.verbose = verbose
|
||||
|
||||
def isusable(s):
|
||||
try:
|
||||
Tk().destroy()
|
||||
return 1
|
||||
except TclError:
|
||||
return 0
|
||||
|
||||
def _createTopWindow(self):
|
||||
self.top = Tk()
|
||||
self.top.title(version.productname + " " + version.versionstr)
|
||||
self.threadframes = {}
|
||||
self.availablethreadframes = []
|
||||
self.tflock = Lock()
|
||||
self.notdeleted = 1
|
||||
|
||||
t = threadutil.ExitNotifyThread(target = self._runmainloop,
|
||||
name = "Tk Mainloop")
|
||||
t.setDaemon(1)
|
||||
t.start()
|
||||
|
||||
t = threadutil.ExitNotifyThread(target = self.idlevacuum,
|
||||
name = "Tk idle vacuum")
|
||||
t.setDaemon(1)
|
||||
t.start()
|
||||
|
||||
def _runmainloop(s):
|
||||
s.top.mainloop()
|
||||
s.notdeleted = 0
|
||||
|
||||
def getpass(s, accountname, config):
|
||||
pd = PasswordDialog(accountname, config)
|
||||
return pd.getpassword()
|
||||
|
||||
def gettf(s):
|
||||
threadid = thread.get_ident()
|
||||
s.tflock.acquire()
|
||||
try:
|
||||
if threadid in s.threadframes:
|
||||
return s.threadframes[threadid]
|
||||
if len(s.availablethreadframes):
|
||||
tf = s.availablethreadframes.pop(0)
|
||||
tf.setthread(currentThread())
|
||||
else:
|
||||
tf = ThreadFrame(s.top)
|
||||
s.threadframes[threadid] = tf
|
||||
return tf
|
||||
finally:
|
||||
s.tflock.release()
|
||||
|
||||
def _msg(s, msg):
|
||||
s.gettf().setmessage(msg)
|
||||
|
||||
def threadExited(s, thread):
|
||||
threadid = thread.threadid
|
||||
s.tflock.acquire()
|
||||
if threadid in s.threadframes:
|
||||
tf = s.threadframes[threadid]
|
||||
tf.setthread(None)
|
||||
tf.setaccount("Unknown")
|
||||
tf.setmessage("Idle")
|
||||
s.availablethreadframes.append(tf)
|
||||
del s.threadframes[threadid]
|
||||
s.tflock.release()
|
||||
|
||||
def idlevacuum(s):
|
||||
while s.notdeleted:
|
||||
time.sleep(10)
|
||||
s.tflock.acquire()
|
||||
while len(s.availablethreadframes):
|
||||
tf = s.availablethreadframes.pop()
|
||||
tf.destroy()
|
||||
s.tflock.release()
|
||||
|
||||
def threadException(s, thread):
|
||||
msg = "Thread '%s' terminated with exception:\n%s" % \
|
||||
(thread.getName(), thread.getExitStackTrace())
|
||||
print msg
|
||||
|
||||
s.top.destroy()
|
||||
s.top = None
|
||||
TextOKDialog("Thread Exception", msg)
|
||||
s.terminate(100)
|
||||
|
||||
def mainException(s):
|
||||
sbuf = StringIO()
|
||||
traceback.print_exc(file = sbuf)
|
||||
msg = "Main program terminated with exception:\n" + sbuf.getvalue()
|
||||
print msg
|
||||
|
||||
s.top.destroy()
|
||||
s.top = None
|
||||
TextOKDialog("Main Program Exception", msg)
|
||||
|
||||
def warn(s, msg):
|
||||
TextOKDialog("OfflineIMAP Warning", msg)
|
||||
|
||||
def init_banner(s):
|
||||
s._createTopWindow()
|
||||
s._msg(version.productname + " " + version.versionstr + ", " +\
|
||||
version.copyright)
|
||||
tf = s.gettf().getthreadextraframe()
|
||||
|
||||
def showlicense():
|
||||
TextOKDialog(version.productname + " License",
|
||||
version.bigcopyright + "\n" +
|
||||
version.homepage + "\n\n" + version.license,
|
||||
blocking = 0, master = tf)
|
||||
b = Button(tf, text = "About", command = showlicense)
|
||||
b.pack(side = LEFT)
|
||||
|
||||
b = Button(tf, text = "Exit", command = s.terminate)
|
||||
b.pack(side = RIGHT)
|
||||
|
||||
def deletingmessages(s, uidlist, destlist):
|
||||
ds = s.folderlist(destlist)
|
||||
s._msg("Deleting %d messages in %s" % (len(uidlist), ds))
|
||||
|
||||
def _sleep_cancel(s, args = None):
|
||||
s.sleeping_abort = 1
|
||||
|
||||
def sleep(s, sleepsecs):
|
||||
s.sleeping_abort = 0
|
||||
tf = s.gettf().getthreadextraframe()
|
||||
|
||||
sleepbut = Button(tf, text = 'Sync immediately',
|
||||
command = s._sleep_cancel)
|
||||
sleepbut.pack()
|
||||
UIBase.sleep(s, sleepsecs)
|
||||
|
||||
def sleeping(s, sleepsecs, remainingsecs):
|
||||
if remainingsecs:
|
||||
s._msg("Next sync in %d:%02d" % (remainingsecs / 60,
|
||||
remainingsecs % 60))
|
||||
else:
|
||||
s._msg("Wait done; synchronizing now.")
|
||||
s.gettf().destroythreadextraframe()
|
||||
time.sleep(sleepsecs)
|
||||
return s.sleeping_abort
|
||||
|
||||
################################################## Copied from TTY
|
||||
|
||||
def syncingmessages(s, sr, sf, dr, df):
|
||||
if s.verbose:
|
||||
UIBase.syncingmessages(s, sr, sf, dr, df)
|
||||
|
||||
def loadmessagelist(s, repos, folder):
|
||||
if s.verbose:
|
||||
UIBase.syncingmessages(s, repos, folder)
|
||||
|
||||
def messagelistloaded(s, repos, folder, count):
|
||||
if s.verbose:
|
||||
UIBase.messagelistloaded(s, repos, folder, count)
|
||||
|
171
offlineimap/head/offlineimap/ui/UIBase.py
Normal file
171
offlineimap/head/offlineimap/ui/UIBase.py
Normal file
@ -0,0 +1,171 @@
|
||||
# UI base class
|
||||
# Copyright (C) 2002 John Goerzen
|
||||
# <jgoerzen@complete.org>
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
from offlineimap import repository
|
||||
import offlineimap.version
|
||||
import re, time, sys, traceback
|
||||
from StringIO import StringIO
|
||||
|
||||
class UIBase:
|
||||
################################################## UTILS
|
||||
def _msg(s, msg):
|
||||
"""Generic tool called when no other works."""
|
||||
raise NotImplementedException
|
||||
|
||||
def warn(s, msg):
|
||||
s._msg("WARNING: " + msg)
|
||||
|
||||
def getnicename(s, object):
|
||||
prelimname = str(object.__class__).split('.')[-1]
|
||||
# Strip off extra stuff.
|
||||
return re.sub('(Folder|Repository)', '', prelimname)
|
||||
|
||||
def isusable(s):
|
||||
"""Returns true if this UI object is usable in the current
|
||||
environment. For instance, an X GUI would return true if it's
|
||||
being run in X with a valid DISPLAY setting, and false otherwise."""
|
||||
return 1
|
||||
|
||||
################################################## INPUT
|
||||
|
||||
def getpass(s, accountname, config):
|
||||
raise NotImplementedException
|
||||
|
||||
def folderlist(s, list):
|
||||
return ', '.join(["%s[%s]" % (s.getnicename(x), x.getname()) for x in list])
|
||||
|
||||
################################################## MESSAGES
|
||||
|
||||
def init_banner(s):
|
||||
"""Called when the UI starts. Must be called before any other UI
|
||||
call except isusable(). Displays the copyright banner. This is
|
||||
where the UI should do its setup -- TK, for instance, would
|
||||
create the application window here."""
|
||||
s._msg(offlineimap.version.banner)
|
||||
|
||||
def acct(s, accountname):
|
||||
s._msg("***** Processing account %s" % accountname)
|
||||
|
||||
def syncfolders(s, srcrepos, destrepos):
|
||||
s._msg("Copying folder structure from %s to %s" % \
|
||||
(s.getnicename(srcrepos), s.getnicename(destrepos)))
|
||||
|
||||
############################## Folder syncing
|
||||
def syncingfolder(s, srcrepos, srcfolder, destrepos, destfolder):
|
||||
"""Called when a folder sync operation is started."""
|
||||
s._msg("Syncing %s: %s -> %s" % (srcfolder.getname(),
|
||||
s.getnicename(srcrepos),
|
||||
s.getnicename(destrepos)))
|
||||
|
||||
def validityproblem(s, folder):
|
||||
s.warn("UID validity problem for folder %s; skipping it" % \
|
||||
folder.getname())
|
||||
|
||||
def loadmessagelist(s, repos, folder):
|
||||
s._msg("Loading message list for %s[%s]" % (s.getnicename(repos),
|
||||
folder.getname()))
|
||||
|
||||
def messagelistloaded(s, repos, folder, count):
|
||||
s._msg("Message list for %s[%s] loaded: %d messages" % \
|
||||
(s.getnicename(repos), folder.getname(), count))
|
||||
|
||||
############################## Message syncing
|
||||
|
||||
def syncingmessages(s, sr, sf, dr, df):
|
||||
s._msg("Syncing messages %s[%s] -> %s[%s]" % (s.getnicename(sr),
|
||||
sf.getname(),
|
||||
s.getnicename(dr),
|
||||
df.getname()))
|
||||
|
||||
def copyingmessage(s, uid, src, destlist):
|
||||
ds = s.folderlist(destlist)
|
||||
s._msg("Copy message %d %s[%s] -> %s" % (uid, s.getnicename(src),
|
||||
src.getname(), ds))
|
||||
|
||||
def deletingmessage(s, uid, destlist):
|
||||
ds = s.folderlist(destlist)
|
||||
s._msg("Deleting message %d in %s" % (uid, ds))
|
||||
|
||||
def deletingmessages(s, uidlist, destlist):
|
||||
ds = s.folderlist(destlist)
|
||||
s._msg("Deleting %d messages (%s) in %s" % \
|
||||
(len(uidlist),
|
||||
", ".join([str(u) for u in uidlist]),
|
||||
ds))
|
||||
|
||||
def addingflags(s, uid, flags, destlist):
|
||||
ds = s.folderlist(destlist)
|
||||
s._msg("Adding flags %s to message %d on %s" % \
|
||||
(", ".join(flags), uid, ds))
|
||||
|
||||
def deletingflags(s, uid, flags, destlist):
|
||||
ds = s.folderlist(destlist)
|
||||
s._msg("Deleting flags %s to message %d on %s" % \
|
||||
(", ".join(flags), uid, ds))
|
||||
|
||||
################################################## Threads
|
||||
|
||||
def threadException(s, thread):
|
||||
"""Called when a thread has terminated with an exception.
|
||||
The argument is the ExitNotifyThread that has so terminated."""
|
||||
s._msg("Thread '%s' terminated with exception:\n%s" % \
|
||||
(thread.getName(), thread.getExitStackTrace()))
|
||||
s.terminate(100)
|
||||
|
||||
def mainException(s):
|
||||
sbuf = StringIO()
|
||||
traceback.print_exc(file = sbuf)
|
||||
s._msg("Main program terminated with exception:\n" +
|
||||
sbuf.getvalue())
|
||||
|
||||
def terminate(s, exitstatus = 0):
|
||||
"""Called to terminate the application."""
|
||||
sys.exit(exitstatus)
|
||||
|
||||
def threadExited(s, thread):
|
||||
"""Called when a thread has exited normally. Many UIs will
|
||||
just ignore this."""
|
||||
pass
|
||||
|
||||
################################################## Other
|
||||
|
||||
def sleep(s, sleepsecs):
|
||||
"""This function does not actually output anything, but handles
|
||||
the overall sleep, dealing with updates as necessary. It will,
|
||||
however, call sleeping() which DOES output something.
|
||||
|
||||
Returns 0 if timeout expired, 1 if there is a request to cancel
|
||||
the timer, and 2 if there is a request to abort the program."""
|
||||
|
||||
abortsleep = 0
|
||||
while sleepsecs > 0 and not abortsleep:
|
||||
abortsleep = s.sleeping(1, sleepsecs)
|
||||
sleepsecs -= 1
|
||||
s.sleeping(0, 0) # Done sleeping.
|
||||
return abortsleep
|
||||
|
||||
def sleeping(s, sleepsecs, remainingsecs):
|
||||
"""Sleep for sleepsecs, remainingsecs to go.
|
||||
If sleepsecs is 0, indicates we're done sleeping.
|
||||
|
||||
Return 0 for normal sleep, or 1 to indicate a request
|
||||
to sync immediately."""
|
||||
s._msg("Next refresh in %d seconds" % remainingsecs)
|
||||
if sleepsecs > 0:
|
||||
time.sleep(sleepsecs)
|
||||
return 0
|
32
offlineimap/head/offlineimap/ui/__init__.py
Normal file
32
offlineimap/head/offlineimap/ui/__init__.py
Normal file
@ -0,0 +1,32 @@
|
||||
# UI module directory
|
||||
# Copyright (C) 2002 John Goerzen
|
||||
# <jgoerzen@complete.org>
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
import UIBase
|
||||
try:
|
||||
import TTY
|
||||
except ImportError:
|
||||
pass
|
||||
try:
|
||||
import Tkinter
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
import Tk
|
||||
|
||||
import detector
|
40
offlineimap/head/offlineimap/ui/detector.py
Normal file
40
offlineimap/head/offlineimap/ui/detector.py
Normal file
@ -0,0 +1,40 @@
|
||||
# UI base class
|
||||
# Copyright (C) 2002 John Goerzen
|
||||
# <jgoerzen@complete.org>
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
from offlineimap.ui import *
|
||||
import sys
|
||||
|
||||
def findUI(config):
|
||||
uistrlist = ['Tk.TkUI', 'TTY.TTYUI']
|
||||
if config.has_option("general", "ui"):
|
||||
uistrlist = config.get("general", "ui").replace(" ", "").split(",")
|
||||
for uistr in uistrlist:
|
||||
uimod = getUImod(uistr)
|
||||
if uimod:
|
||||
uiinstance = uimod()
|
||||
if uiinstance.isusable():
|
||||
return uiinstance
|
||||
sys.stderr.write("ERROR: No UIs were found usable!\n")
|
||||
sys.exit(200)
|
||||
|
||||
def getUImod(uistr):
|
||||
try:
|
||||
uimod = eval(uistr)
|
||||
except (AttributeError, NameError):
|
||||
return None
|
||||
return uimod
|
84
offlineimap/head/offlineimap/version.py
Normal file
84
offlineimap/head/offlineimap/version.py
Normal file
@ -0,0 +1,84 @@
|
||||
productname = 'OfflineIMAP'
|
||||
versionstr = "3.0.2"
|
||||
revno = long('$Rev: 128 $'[6:-2])
|
||||
revstr = "Rev %d" % revno
|
||||
datestr = '$Date: 2002-07-17 13:06:27 -0500 (Wed, 17 Jul 2002) $'
|
||||
|
||||
versionlist = versionstr.split(".")
|
||||
major = versionlist[0]
|
||||
minor = versionlist[1]
|
||||
patch = versionlist[2]
|
||||
copyright = "Copyright (C) 2002 John Goerzen"
|
||||
author = "John Goerzen"
|
||||
author_email = "jgoerzen@complete.org"
|
||||
description = "Disconnected Universal IMAP Mail Synchronization/Reader Support"
|
||||
bigcopyright = """%(productname)s %(versionstr)s (%(revstr)s)
|
||||
%(copyright)s <%(author_email)s>""" % locals()
|
||||
|
||||
banner = bigcopyright + """
|
||||
This software comes with ABSOLUTELY NO WARRANTY; see the file
|
||||
COPYING for details. This is free software, and you are welcome
|
||||
to distribute it under the conditions laid out in COPYING."""
|
||||
|
||||
homepage = "http://www.quux.org/devel/offlineimap"
|
||||
homegopher = "gopher://quux.org/1/devel/offlineimap"
|
||||
license = """Copyright (C) 2002 John Goerzen <jgoerzen@complete.org>
|
||||
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA"""
|
||||
|
||||
cmdhelp = """
|
||||
offlineimap [ -1 ] [ -a accountlist ] [ -c configfile ]
|
||||
[ -d ] [ -u interface ]
|
||||
|
||||
offlineimap -h | --help
|
||||
|
||||
-1 Disable all multithreading operations and use
|
||||
solely a single-thread sync. This effectively sets
|
||||
the maxsyncaccounts and all maxconnections configu-
|
||||
ration file variables to 1.
|
||||
|
||||
-a accountlist
|
||||
Overrides the accounts section in the config file.
|
||||
Lets you specify a particular account or set of
|
||||
accounts to sync without having to edit the config
|
||||
file. You might use this to exclude certain
|
||||
accounts, or to sync some accounts that you nor-
|
||||
mally prefer not to.
|
||||
|
||||
-c configfile
|
||||
Specifies a configuration file to use in lieu of
|
||||
the default, ~/.offlineimaprc.
|
||||
|
||||
-d Enables IMAP protocol stream and parsing debugging.
|
||||
This is useful if you are trying to track down a
|
||||
malfunction or figure out what is going on under
|
||||
the hood. I suggest that you use this with -1 in
|
||||
order to make the results more sensible. Note that
|
||||
this output will contain full IMAP protocol in
|
||||
plain text, including passwords, so take care to
|
||||
remove that from the debugging output before send-
|
||||
ing it to anyone else.
|
||||
|
||||
-h, --help
|
||||
Show summary of options.
|
||||
|
||||
-u interface
|
||||
Specifies an alternative user interface module to
|
||||
use. This overrides the default specified in the
|
||||
configuration file. The UI specified with -u will
|
||||
be forced to be used, even if its isuable() method
|
||||
states that it cannot be. Use this option with
|
||||
care.
|
||||
"""
|
40
offlineimap/head/setup.py
Normal file
40
offlineimap/head/setup.py
Normal file
@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env python2.2
|
||||
|
||||
# $Id: setup.py,v 1.1 2002/06/21 18:10:49 jgoerzen Exp $
|
||||
|
||||
# IMAP synchronization
|
||||
# Module: installer
|
||||
# COPYRIGHT #
|
||||
# Copyright (C) 2002 John Goerzen
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
# END OF COPYRIGHT #
|
||||
|
||||
|
||||
from distutils.core import setup
|
||||
import offlineimap.version
|
||||
|
||||
setup(name = "offlineimap",
|
||||
version = offlineimap.version.versionstr,
|
||||
description = offlineimap.version.description,
|
||||
author = offlineimap.version.author,
|
||||
author_email = offlineimap.version.author_email,
|
||||
url = offlineimap.version.homepage,
|
||||
packages = ['offlineimap', 'offlineimap.folder',
|
||||
'offlineimap.repository', 'offlineimap.ui'],
|
||||
scripts = ['offlineimap.py'],
|
||||
license = offlineimap.version.license
|
||||
)
|
||||
|
Reference in New Issue
Block a user