Commit Graph

73 Commits

Author SHA1 Message Date
Sebastian Spaeth
4eeb88dd8f Append, don't truncate, log file
The new logging handler was truncating the log file on each start.
Append by default.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2011-11-02 10:56:42 +01:00
Sebastian Spaeth
7c45e05428 Fix getExitStackTrace call
It was changed
2011-10-27 17:45:00 +02:00
Sebastian Spaeth
d992c66156 Rework the whole unused get/setExitCause machinery
It is basically unused by now. Rework to be able to make use of it
later, no functional changes.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2011-10-27 17:23:43 +02:00
Sebastian Spaeth
8195d1410f Prettify Blinkenlights.sleep()
Prettify the function.
Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2011-10-27 16:58:44 +02:00
Sebastian Spaeth
cbec8bb5b2 Rework UI system to make use of the logging module
Logging was flawed as the output was e.g. heavily buffered and people
complained about missing log entries. Fix this by making use of the
standard logging facilities that offlineimap offers.

This is one big ugly patch that does many things. It fixes the
Blinkenlights backend to work again with the logging facilities.

Resize windows and hotkeys are still not handled absolut correctly, this
is left for future fixing. THe rest of the backends should be working fine.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2011-10-27 16:23:55 +02:00
Sebastian Spaeth
0ba9634205 Fix string formatting when port is not given.
If port is None, we would try to format an empty string with %d wich
fails. Fix it by using %s.

Reported-by: Iain Dalton <iain.dalton@gmail.com>
Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2011-09-30 10:59:07 +02:00
Sebastian Spaeth
3885acf87d Implement server diagnostics
This outputs a handy summary of your server configuration and version
strings etc, which is useful for bug reporting.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2011-09-30 09:41:45 +02:00
Sebastian Spaeth
a5eebd4b6b Make "syncing folder structure" a debug level log entry
It happens quick, and clutters the log. So we can usually skip this. We
will output a log entry when we actually create a new folder anyway.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2011-09-30 09:21:03 +02:00
Sebastian Spaeth
ac94de3449 Only output a sleeping notice once every minute
Rather than every ten seconds, which is a bit chatty.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2011-09-29 17:58:07 +02:00
Sebastian Spaeth
93b05215fb Condense ui.connecting() function a bit
Just tiny non-functional code cleanup.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2011-09-29 17:47:14 +02:00
Sebastian Spaeth
3b647d65be Output sync timing
Modify the UI:acct and acctdone functions to keep tab of the time
inbetween. Put self.ui.acct() and acctdone() at the right places in
accounts.py so that the timing happens at the right places.

While modifying that loop, flatten the nested try: try: except: finally:
constructs, we require python 2.5 now which copes with that.

At the end of each account sync you will now see something like:
*** Finished account 'test' in 0:05

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2011-09-29 17:26:46 +02:00
Sebastian Spaeth
eb0b546927 Output progress indication when copying files
Output (2 of 500) when logging message copying. This required moving of
self.ui.copyingmessage into a different function where we actually have
the information about the progress handy.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2011-09-29 16:51:48 +02:00
Sebastian Spaeth
8970a1500b UIBase: Fix and cleanup register/unregisterthread
Registering a thread (associating it with a certain account name) would
fail if it was already registered. However, as we a) never unregister most
threads (bad) and b) single-threaded mode reuses threads, we failed when
syncing multiple accounts in single-threading mode.

This commit cleans up the functions to not make re-registering a thread
fatal (it could be legitimate, however it *should* not occur). Future
work needs to be done to unregister new threads at the appropriate places.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2011-09-29 15:44:30 +02:00
Sebastian Spaeth
ae8a1cb79f Remove deprecated calls to apply()
apply() has been deprecated since Python 2.3, and won't be working in
python 3 anymore. Use the functional equivalent throughout.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2011-09-27 13:00:12 +02:00
Sebastian Spaeth
48fdb14418 Don't output thread ID in log
The thread ID is not really useful and looks ugly. It also makes lines
longer than needed, there is more useful information we can put in the
log. So do away with it.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2011-09-19 19:59:39 +02:00
Sebastian Spaeth
19ff636390 Properly output errors when the main thread receives some
Use the ui.error infrastructure that has been put in place and use
ui.terminate even if we received an Exception, so that we can output the
list of errors that we have. This does away with 2 now unused functions
in ui/UIBase.py

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
2011-09-19 09:34:25 +02:00
Sebastian Spaeth
6295d64d54 Shorten list of messages to be deleted in UI output
Rather than output the full list of messages, coalesce it into number
ranges wherever possible.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-08-23 20:55:28 +02:00
Sebastian Spaeth
4f1cd05fdc Fix copyingmessage() in Machine UI
I changed the API to pass in a folder rather than a list of folders, but
used getnicename() on the wrong object. It is not used on the folder but
on the ui object. Fix this and give the variable somewhat better names.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-08-19 18:25:04 +02:00
Sebastian Spaeth
6f9b171ffd Don't pass a list to ui.copyingmessage()
We only copy to a single folder anyway, so clean up the code to only
pass in a single folder.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-08-17 20:41:32 +02:00
Sebastian Spaeth
634b6cd49e Don't make Blinkenlight statuschar configurable
Allowing to specify the char to use in the BLinkenlights is a bit over
the top and bloats our default offlineimap.conf. The dot is just fine,
so let us settle for it and cut the example config file by an unneeded
section.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-08-15 12:10:20 +02:00
Sebastian Spaeth
51629b8ffe Update example in code documentation of ui.error()
sys.exc_traceback is long deprecated and is seems removed in python2.7,
so document the legitimate use of sys.exc_info()[2] instead.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-08-14 17:18:51 +02:00
Sebastian Spaeth
f937a86571 Implement ui.error() and output them at end of offlinimap sync
Output all raised Exceptions error strings to the error log. If we are
in debug mode, we also output the traceback of the exception.

Save all exceptions that occur during the run time to a Queue and output
them all again when the offlineimap sync is finished.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-08-11 19:14:28 +02:00
Sebastian Spaeth
8e2589982c Don't use CStringIO to format a traceback
The traceback module has format_exc() for this purpose so let's use that.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-06-30 21:28:06 +02:00
Nicolas Sebrecht
d5493fe894 threadutil: explicitly import get_ident from thread
The python module thread is the low-level module we should avoid to use in favor
of threading. We still need it to support old python because Thread.ident
doesn't exist before python 2.6:

	http://docs.python.org/library/threading.html#threading.Thread.ident

Make it clear we should avoid it.

Reviewed-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-05-12 18:28:49 +02:00
Nicolas Sebrecht
8a34edc8ca cleanup import satements
- conform to PEP8
- explicitly define symbols instead of 'import *'
- remove unused import

Reviewed-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-05-12 18:26:29 +02:00
Sebastian Spaeth
89619838b0 Remove weird SigListener class
The SigListener class was used to queue folders that we need to sync and
to receive "resync" and "abort" signals. It was undocumented and weird
and we had to pass "siglisteners" through the whole program.

Simply do away with it, and make 2 functions in the Account() class:
set_abort_event and get_abort_event which can be used to set and check
for such signals. This way we do not need to pass siglisteners all over
the place. Tested Blinkenlights and TTYUI uis to make sure that SIGUSR1
and SIGUSR2 actually still work.

Document those signals in MANUAL.rst. They were completly undocumented.

This simplifies the code and interdependencies by passing less stuff
around. Removes an undocumented and weirdly named class.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-05-08 14:25:16 +02:00
Sebastian Spaeth
bd3766eca5 Make getnicename work again for classes that derive from object()
Python's new style classes derive from object and str(class().__class__)
will return a slightly different format. class().__class.__name__ will
still work for both old and new style classes, so use that instead.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-05-07 13:29:11 +02:00
Nicolas Sebrecht
c6259fbb86 Merge branch 'master' into next
Conflicts:
	Changelog.draft.rst
2011-05-05 21:16:02 +02:00
Sebastian Spaeth
deab62fbd8 Fix the broken thread debugging
Using threading._VERBOSE=1 is broken since python 2.6 till at least
python 3.2, (http://bugs.python.org/issue4188) so we can't use it for
our thread debugging.

Remove the usage of threading._VERBOSE, and implement a "light thread
debug log" that for now outputs information when a new thread is being
registered and when it is being unregistered. I am sure we will be able
to add more thread debugging information over the time.

Besides '-d thread' this will re-enable the usage of -d 'all' for the
most verbose debugging of all categories.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-05-05 21:07:24 +02:00
Sebastian Spaeth
3d4dc11a8b Introduce an *empty* debug type
This debug type will always be enabled whenever any debugging is enables
and it outputs debug messages that cannot be categorized among any of
imap, maildir (e.g. things that concern the sync logic).

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-05-02 20:41:36 +02:00
Sebastian Spaeth
6add201436 Improve the developer API documentation
Improve the code documentation (still much more to do) and also add some
more meat to the structure of the developer documentation.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-05-02 20:16:45 +02:00
Nicolas Sebrecht
44eefae043 cleanup import statements and conform to PEP-8
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-03-14 21:35:33 +01:00
Nicolas Sebrecht
90949a4bfc UIBase: fix regression while deletingflags
In commit 7a2a0225 [Don't pass list to ui.adding/deletingflags] we changed the
list logic for a per folder logic but forgot to remove one instance of
"destlist" which isn't valid anymore.

Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-03-11 20:20:12 +01:00
Nicolas Sebrecht
5048d16913 Merge branch 'ss/declutter-tty-output' into next
Conflicts:
	Changelog.draft.rst
2011-03-10 19:26:26 +01:00
Sebastian Spaeth
efcce01d64 Declutter TTY output
Previously we would output:

Folder sync sspaeth.de[INBOX.INBOX201004]:
 Syncing INBOX.INBOX201004: IMAP -> Maildir
Folder sync sspaeth.de[INBOX.INBOX201006]:
 Syncing INBOX.INBOX201006: IMAP -> Maildir
Folder sync sspaeth.de[INBOX.INBOX201009]:
 Syncing INBOX.INBOX201009: IMAP -> Maildir

which is very repetitive and cluttered. By naming the folder sync
threads just according to the account and not the folder, the output
looks much nicer:

Folder sync [sspaeth.de]:
 Syncing INBOX.INBOX201004: IMAP -> Maildir
 Syncing INBOX.INBOX201006: IMAP -> Maildir
 Syncing INBOX.INBOX201009: IMAP -> Maildir

If syncing multiple accounts in parallel, we will still get headers
indicating the account:

Folder sync [sspaeth.de]:
 Syncing INBOX: IMAP -> Maildir
 Syncing INBOX.INBOX201006: IMAP -> Maildir
Folder sync [gmail]:
 Syncing INBOX: IMAP -> Maildir

This is a small fix that makes the output much nicer in my opinion.

Also don't output the thread name if we are in the MainThread, e.g. when
we output the initial offlineimap banner.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-03-10 19:04:57 +01:00
Sebastian Spaeth
7a2a02254e Don't pass list to ui.adding/deletingflags
We only have one "dstfolder" at a time when deleting/adding flags, so no
need to pass in a list of those to the ui functions that output the log
info.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-03-07 21:11:10 +01:00
Sebastian Spaeth
387fbf3aaa ui: clean up importment statements
They were not PEP-8 formatted, and some imports were simply
unnecessary. Removed those.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-03-07 21:11:10 +01:00
Sebastian Spaeth
4e28c7c93f Allow to use nicer UI names
The previous ui names were pretty unwieldy. Is it TTYUI.TTY or
TTY.TTYUI? Do I have to use capitals and where?

Simplify the names by making them case insensitive and by dropping
everything before the dot.

So "Curses.Blinkenlights" can now be invoked as "blinkenlights" or
"BLINKENLIGHTS". The old names will still work just fine so the
transition should be smooth. We issue a warning that the long names are
deprecated.

Document in offlineimap.conf that we don't accept lists of fallback UIs,
but only one UI option (this was already the case before this commit but
still wrongly documented).

The list of accepted ui names is:
  ttyui (default), basic, quiet, machineui, blinkenlights

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-03-06 15:33:29 +01:00
Nicolas Sebrecht
72d05bac09 restore compatibilty with python 2.5 for ui TTY
threading.currentThread() used an accessor to get its name.

Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-02-18 20:00:19 +01:00
Sebastian Spaeth
83a85bb3fb Remove MultiLock implementation
Currently the Curses code is broken. Importing offlineimap.ui.Curses
will not succeed due to cyclic imports (threadutils imports ui, but ui
wants threadutils.MultiLock). So Curses cannot be chosen.

Incidentally, the only part in the code that uses "MultiLock" is the
Curses UI, to prevent concurrent access from several threads to the
ui-internal thread list and to IO resources such as the
screen. Fortunately for these purposes we don't need a MultiLock, so we
can do away with that implementation completely. A simple RLock that
allows us to have a thread "own" a lock and makes other threads wanting
access to the resource wait until the owning thread is finished.

The MultiLock implementation looked a bit weird, so simplifying code
here is a good thing, it might well be that we fix some "hangs" that
have been reported (and that would only ever occur with the Curses UI).

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-01-25 19:19:14 +01:00
Thomas Schwinge
fa60f3f9b7 offlineimap.version is no more.
This fixes some leftover of 0b5b38d298.

Signed-off-by: Thomas Schwinge <thomas@schwinge.name>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-01-25 18:36:18 +01:00
Nicolas Sebrecht
43096ad378 Merge branch 'ss/ui-remove-detector' into next 2011-01-07 19:38:12 +01:00
Sebastian Spaeth
c3540de763 Remove ui.detector class
The ui.detector class was not really needed and leads to the illusion
that we provide GUI plugins. For the sake of code maintainability we
don't :-).

Rather than having GUI names equivalent to the classes they are in
(which leads to weird names like TTY.TTYUI), this patch allows to give
each GUI an arbitrary string name. GUI names remain still unchanged in
this patch, the default UI when none was configured is TTY.TTYUI.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2011-01-07 19:37:48 +01:00
Sebastian Spaeth
0b5b38d298 Define version constants etc in __init__.py
Move central constant definitions into __init__.py.  This does away
with version.py which contained nothing else and __init__.py is where
things like __VERSION__ are usually defined.

This commit also changes code to use offlineimap.__version__ rather
than offlineimap.version.__version__ as was before. Cleaned up some
duplicate or unneeded imports while touching those, formatting import
statements per PEP8 (one import per row).

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2010-12-22 19:45:01 +01:00
Sebastian Spaeth
35dd236155 Improve TTY ui to not always prepend 'sync account foo'
This is very excessive and a bit annoying. Output that information
only if the next line concerns a different account/thread than the
previous one. This quiets down the UI quite a bit without losing
information.

While modifying this line, use the newer Thread.name and not the as
per python doc's old syntax getName()

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2010-12-09 19:52:48 +01:00
Sebastian Spaeth
f68b626cb4 Don't display sleeping every second on the screen
Only every 10 seconds. Also fix up the documentation of that function
while at it. The Curses ui actually implements user abort it
seems. Not sure if we could do the same in the UIBase, but that is for
another time.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2010-12-09 19:52:48 +01:00
Sebastian Spaeth
6e62da435b Fix Machine ui to not error out on ui.warn()
All other uis (especially BaseUI) define as warn(self, msg, minor = 0)
just MachineUI required minor without a default. This leads the
Machine UI to error out with an exception if we pass it
ui.warn("string") which is the common thing in our code base. This
patch is therefore small but critical in fixing this UI.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
2010-12-09 19:52:48 +01:00
buergi
9239a2d326 Bugfix patch for offlineimap
Hello John,

i fixed some tiny bugs in offlineimap, mainly just for myself. They are
more dirty fixes than real bugfixes since I'm missing the deeper insight
into the code.
Especially the first one for Curses.py is very dirty and breaks the
scaling of the interface when the terminal size changes, but at least
the terminal is in proper state after exiting offlineimap.

In the order of appearance in the patchfile:
1. 'fixes' terminal breakage on quit of curses interface in python 2.6
to 2.6.5 (fixed since 2.6.6 http://bugs.python.org/issue7567)
2. fixes netrc password authentication
3. fixes user name querying from netrc

The patch is made for git revision 6b1cb5e036

Thanks a lot for the great application!

Best regards,
buergi
2010-08-20 08:29:47 -05:00
John Goerzen
e1fb9492f8 Patch for signal handling to start a sync by Jim Pryor
Here's the way I'd like to use offlineimap on my laptop:
    1. Have a regular cron job running infrequently. The cron job
    checks to see
if I'm online, plugged in, and that no other copy of offlineimap is
running. If
all of these conditions are satisfied, it runs offlineimap just once:
"offlineimap -o -u Noninteractive.Quiet"

    2. When I start up mutt, I do it by calling a wrapper script that
    delays
until cron-started copies of offlineimap have finished, then starts
    offlineimap
on its regular, stay-alive and keep checking schedule. When I quit
    mutt, the
wrapper script tells offlineimap to stop.

This way I get frequent regular checks while I have mutt running, but
I don't
waste my battery/cpu checking frequently for mail when I'm not
interested in
it.

To make this work, though, it'd be nicer if it were easier to tell
offlineimap,
from the outside, things like "terminate cleanly now" and "when you've
finished
synching, then terminate instead of sleeping and synching again."

OK, to put my money where my mouth is, I attach two patches against
offlineimap
6.0.3.

The first, "cleanup.patch", cleans up a few spots that tend to throw
exceptions
for me as offlineimap is exiting from a KeyboardInterrupt.

The second adds signaling capabilities to offlineimap.

* sending a SIGTERM tells offlineimap to terminate immediately but
  cleanly,
  just as if "q" had been pressed in the GUI interface

* sending a SIGUSR1 tells every account to do a full sync asap: if
  it's
  sleeping, then wake up and do the sync now. If it's mid-sync, then
  re-synch
  any folders whose syncing has already been started or completed, and
  continue
  to synch the other, queued but not-yet-synched folders.

* sending a SIGHUP tells every account to die as soon as it can (but
  not
  immediately: only after finishing any synch it's now engaged in)

* sending a SIGUSR2 tells every account to do a full sync asap (as
  with
  SIGUSR1), then die

It's tricky to mix signals with threads, but I think I've done this
correctly.
I've been using it now for a few weeks without any obvious
problems. But I'm passing it
on so that others can review the code and test it out on their
systems. I developed the
patch when I was running Python 2.5.2, but to my knowledge I don't use
any Python 2.5-specific
code. Now I'm using the patch with Python 2.6.

Although I said "without any obvious problems," let me confess that
I'm
seeing offlineimap regularly choke when I do things like this: start
up
my offlineimap-wrapped copy of mutt, wait a while, put the machine to
sleep (not sure if offlineimap is active in the background or idling),
move to a different spot, wake the machine up again and it acquires a
new network, sometimes a wired network instead of wifi. Offlineimap
doesn't like that so much. I don't yet have any reason to think the
problems here come from my patches. But I'm just acknowledging them,
so
that if others are able to use offlineimap without any difficulty in
situations like I described, then maybe the fault is with my patches.
2008-12-01 16:13:16 -06:00
John Goerzen
ab43d74549 Applied pre/post sync hooks
Patch from Sylvain FORET in refs #71
2008-10-01 00:03:04 -05:00