diff --git a/ChangeLog b/ChangeLog index c833a49..e261924 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,17 +1,26 @@ RCS file: RCS/imapsync,v Working file: imapsync -head: 1.516 +head: 1.518 branch: locks: strict - gilles: 1.516 + gilles: 1.518 access list: symbolic names: keyword substitution: kv -total revisions: 516; selected revisions: 516 +total revisions: 518; selected revisions: 518 description: ---------------------------- -revision 1.516 locked by: gilles; +revision 1.518 locked by: gilles; +date: 2012/12/24 00:27:34; author: gilles; state: Exp; lines: +9 -6 +Bugfix. When identtifying with header, change tabulations to spaces (Gmail bug on with "Received:" on multilines). +---------------------------- +revision 1.517 +date: 2012/12/11 07:13:04; author: gilles; state: Exp; lines: +17 -10 +Added Deerfield VisNetic MailServer 5.8.6 +Bugfix. Automatic --nocheckmessageexists when --noabletosearch is set. +---------------------------- +revision 1.516 date: 2012/11/02 22:15:04; author: gilles; state: Exp; lines: +43 -38 Added current date at the beginning of the run, useful when imapsync doesn't end properly or hasn't finished yet. Better output for diff statistics. diff --git a/FAQ b/FAQ index 3f4e725..d9aac5c 100644 --- a/FAQ +++ b/FAQ @@ -1,5 +1,5 @@ #!/bin/cat -# $Id: FAQ,v 1.117 2012/11/03 00:44:30 gilles Exp gilles $ +# $Id: FAQ,v 1.120 2012/12/15 00:05:42 gilles Exp gilles $ +------------------+ | FAQ for imapsync | @@ -1190,7 +1190,7 @@ Maybe add other --regextrans2 to change folder names and see the result. When satisfied, run without --dry --justfolders ======================================================================= -Q. Synchronizing from XXX to Gmail +Q. Synchronizing from XXX to Gmail R. There are some details to get the special [Gmail] sub-folders right. Here's an example of migrating an old "Sent" folder to @@ -1202,16 +1202,37 @@ imapsync --host1 mail.oldhost.com \ --host2 imap.gmail.com --ssl2 \ --user2 my_email@gmail.com \ --password2 password \ + --exitwhenover 500000000 \ --folder "INBOX.Sent" \ - --regextrans2 "s/Sent/Sent Mail/" \ - --exitwhenover 500000000 + --regextrans2 "s,^Sent$,[Gmail]/Sent Mail," \ + --addheader -The same goes for the "All Mail" archive pseudo-folder. + +If you're using a different language in Gmail you might adapt +this example with the folder name translated, an example in French: + +imapsync ... + --folder 'INBOX.Messages envoy&AOk-s' \ + --regextrans2 "s,^Messages envoy&AOk-s$,[Gmail]/Messages envoy&AOk-s," \ + +The --addheader option is there because Sent folder messages +sometimes lack the "Message-Id" header needed by imapsync +when --useuid is not used. So option --addheader adds a "Message-Id" header. + +You can remove --folder "INBOX.Sent" in the example in case +you want to sync all folders, the --regextrans2 option will +still apply only on "INBOX.Sent" folder. + +The "All Mail" archive pseudo-folder should be updated automaticaly. --exitwhenover option is here to avoid locking when transfers exceed maximum limit. See http://support.google.com/a/bin/answer.py?hl=en&answer=1071518 +You can select folders exported to imap within the gmail preferences, +unselect all "System labels". + + ======================================================================= Q. Synchronizing from Gmail to XXX @@ -1473,6 +1494,17 @@ Q. From Microsoft Exchange 2000 IMAP4rev1 server version 6.0.6487.0. R. imapsync ... \ --prefix1 INBOX. + +====================================================================== +Q. From Softalk Workgroup Mail 7.6.4 + +R. Old Softalk releases don't support the IMAP SEARCH command. + Here are the options to get it working. + +imapsync ... --sep1 '.' --prefix1 '' \ + --noabletosearch --nocheckmessageexists --addheader + +(Thanks to Andrew Tucker) ====================================================================== Q: How can I write an .rpm with imapsync diff --git a/Makefile b/Makefile index fe1d476..341d282 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -# $Id: Makefile,v 1.110 2012/11/03 01:38:12 gilles Exp gilles $ +# $Id: Makefile,v 1.113 2012/12/24 02:24:40 gilles Exp gilles $ .PHONY: help usage all @@ -108,11 +108,11 @@ test_quick_229: imapsync tests.sh test_quick_3xx: imapsync tests.sh CMD_PERL='perl -I./$(IMAPClient_3xx)' /usr/bin/time sh -x tests.sh locallocal -testv2: +testv2: imapsync tests.sh CMD_PERL='perl -I./$(IMAPClient_2xx)' /usr/bin/time sh tests.sh touch .test_229 -testv3: +testv3: imapsync tests.sh CMD_PERL='perl -I./$(IMAPClient_3xx)' /usr/bin/time sh tests.sh touch .test_3xx @@ -138,8 +138,8 @@ testf: clean_test test .PHONY: lfo upload_lfo niouze_lfo niouze_fm public imapsync_cidone -.dosify_bat: W/build_exe.bat W/test_exe.bat W/test.bat W/test2.bat examples/imapsync_example.bat.txt - unix2dos W/build_exe.bat W/test.bat W/test_exe.bat W/test2.bat examples/imapsync_example.bat.txt examples/file.txt +.dosify_bat: W/*.bat examples/*.bat + unix2dos W/*.bat examples/*.bat touch .dosify_bat dosify_bat: .dosify_bat @@ -213,8 +213,14 @@ imapsync_elf_x86.bin: imapsync lfo: cidone niouze_lfo upload_lfo -tarball: cidone all +tarball: .tarball + + +.tarball: imapsync echo making tarball $(DIST_FILE) + rcsdiff RCS/* + cd W && rcsdiff RCS/* + cd examples && rcsdiff RCS/* mkdir -p dist mkdir -p ../prepa_dist/$(DIST_NAME) rsync -aCv --delete --omit-dir-times --exclude dist/ --exclude imapsync.exe ./ ../prepa_dist/$(DIST_NAME)/ @@ -224,6 +230,7 @@ tarball: cidone all cd ../prepa_dist && md5sum $(DIST_FILE) > $(DIST_FILE).md5.txt cd ../prepa_dist && md5sum -c $(DIST_FILE).md5.txt ls -l ../prepa_dist/$(DIST_FILE) + touch .tarball DO_IT := $(shell test -f ./dist/path_$(VERSION).txt || makepasswd --chars 4 > ./dist/path_$(VERSION).txt) @@ -282,7 +289,7 @@ PUBLIC_FILES_W = ./W/style.css \ PUBLIC_FILES_IMAGES = ./W/images/logo_imapsync.png ./W/images/logo_imapsync_s.png -ml: +ml: dist_dir m4 -P W/ml_announce.in | mutt -H- mailq @@ -311,10 +318,12 @@ upload_lfo: /home/gilles/public_html/www.linux-france.org/html/prj/imapsync/.htaccess sh ~/memo/lfo-rsync -upload_index: index.shtml FAQ COPYING CREDITS +upload_index: FAQ COPYING CREDITS W/*.bat examples/*.bat examples/sync_loop_unix.sh index.shtml + rcsdiff index.shtml FAQ COPYING CREDITS W/*.bat examples/*.bat index.shtml validate --verbose index.shtml - rcsdiff index.shtml FAQ COPYING CREDITS rsync -avH index.shtml FAQ COPYING CREDITS root@ks.lamiral.info:/var/www/imapsync/ + rsync -avH W/*.bat root@ks.lamiral.info:/var/www/imapsync/W/ + rsync -avH examples/*.bat examples/sync_loop_unix.sh root@ks.lamiral.info:/var/www/imapsync/examples/ niouze_lfo : echo "CORRECT ME: . ./memo && lfo_announce" diff --git a/README b/README index 19bea6b..316bccf 100644 --- a/README +++ b/README @@ -3,7 +3,7 @@ NAME Synchronise mailboxes between two imap servers. Good at IMAP migration. More than 44 different IMAP server softwares supported with success. - $Revision: 1.516 $ + $Revision: 1.518 $ SYNOPSIS To synchronise imap account "foo" on "imap.truc.org" to imap account @@ -301,7 +301,7 @@ IMAP SERVERS MDaemon is simply buggy with the APPEND IMAP command with any IMAP email client. - Success stories reported with the following 44 imap servers (software + Success stories reported with the following 48 imap servers (software names are in alphabetic order): - 1und1 H mimap1 84498 [host1] @@ -320,6 +320,7 @@ IMAP SERVERS 2.3-alpha (OSI Approved), 2.3.1, 2.3.7, 2.3.16 (http://asg.web.cmu.edu/cyrus/) - David Tobit V8 (proprietary Message system). + - Deerfield VisNetic MailServer 5.8.6 [host1] (http://www.deerfield.net/products/visnetic-mailserver/) - DBMail 1.2.1, 2.0.4, 2.0.9, 2.2rc1 (GPL) (http://www.dbmail.org/). 2.0.7 seems buggy. - Deerfield VisNetic MailServer 5.8.6 [host1] @@ -356,6 +357,7 @@ IMAP SERVERS - Samsung Contact IMAP server 8.5.0 - Scalix v10.1, 10.0.1.3, 11.0.0.431, 11.4.6 - SmarterMail, Smarter Mail 5.0 Enterprise, Smarter Mail 5.5 [host1]. + - Softalk Workgroup Mail 7.6.4 [host1]. - SunONE Messaging server 5.2, 6.0 (SUN JES - Java Enterprise System) - Sun Java(tm) System Messaging Server 6.2-2.05, 6.2-7.05, 6.3 - Surgemail 3.6f5-5 @@ -440,5 +442,5 @@ SIMILAR SOFTWARES Feedback (good or bad) will often be welcome. - $Id: imapsync,v 1.516 2012/11/02 22:15:04 gilles Exp gilles $ + $Id: imapsync,v 1.518 2012/12/24 00:27:34 gilles Exp gilles $ diff --git a/VERSION b/VERSION index c9cb815..449bde6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.516 +1.518 diff --git a/VERSION_EXE b/VERSION_EXE index c9cb815..449bde6 100644 --- a/VERSION_EXE +++ b/VERSION_EXE @@ -1 +1 @@ -1.516 +1.518 diff --git a/W/.BUILD_EXE_TIME b/W/.BUILD_EXE_TIME index c2fec3c..afd3a5f 100644 --- a/W/.BUILD_EXE_TIME +++ b/W/.BUILD_EXE_TIME @@ -160,3 +160,7 @@ 1351689817 END 1.515 : mercredi 31 octobre 2012, 14:23:37 (UTC+0100) 1351894814 BEGIN 1.516 : vendredi 2 novembre 2012, 23:20:14 (UTC+0100) 1351896296 END 1.516 : vendredi 2 novembre 2012, 23:44:56 (UTC+0100) +1356314808 BEGIN 1.518 : lundi 24 décembre 2012, 03:06:48 (UTC+0100) +1356315575 END 1.518 : lundi 24 décembre 2012, 03:19:35 (UTC+0100) +1356340377 BEGIN 1.518 : lundi 24 décembre 2012, 10:12:57 (UTC+0100) +1356341221 END 1.518 : lundi 24 décembre 2012, 10:27:01 (UTC+0100) diff --git a/W/build_exe.bat b/W/build_exe.bat index ba3e82d..5767941 100644 --- a/W/build_exe.bat +++ b/W/build_exe.bat @@ -1,5 +1,6 @@ -REM $Id: build_exe.bat,v 1.9 2011/05/31 08:28:29 gilles Exp gilles $ +REM $Id: build_exe.bat,v 1.11 2012/12/24 02:25:55 gilles Exp gilles $ +REM echo Building imapsync.exe cd C:\msys\1.0\home\Admin\imapsync diff --git a/W/memo b/W/memo index e6df361..e0307c0 100644 --- a/W/memo +++ b/W/memo @@ -1,6 +1,6 @@ #!/bin/sh -# $Id: memo,v 1.41 2012/02/04 23:55:37 gilles Exp gilles $ +# $Id: memo,v 1.43 2012/12/24 02:25:00 gilles Exp gilles $ software_version() { @@ -8,20 +8,8 @@ software_version() { } -statistics_lfo() { -# 62.147.165.21 - - [31/Oct/2010:23:45:28 +0100] "GET /prj/imapsync/VERSION HTTP/1.0" 200 6 "-" "imapsync/1.368 (linux system, perl 5.8.8, Mail::IMAPClient 2.2.9 imapsync)" -#grep prj/imapsync/VERSION /usr/local/apache/logs/access_log | sort -n | cut -d ' ' -f 1,12,13|uniq -c | sort -n # list ip - +statistics_lfo_frequency() { cat < stats_imapsync_${year}_${month}.ip } -echo statistics_VERSION_monthly_ip_wc 02 2012 +echo "statistics_VERSION_monthly_ip_wc 02 2012 # short" statistics_VERSION_monthly_ip_wc() { month=${1:-`date '+%m'`} year=${2:-`date '+%Y'`} @@ -110,7 +90,7 @@ statistics_VERSION_monthly_ip_wc() { wc -l stats_imapsync_${year}_${month}.ip } -echo statistics_VERSION_monthly_runs 02 2012 +echo "statistics_VERSION_monthly_runs 02 2012 # short" statistics_VERSION_monthly_runs() { month=${1:-`date '+%m'`} year=${2:-`date '+%Y'`} @@ -118,7 +98,30 @@ statistics_VERSION_monthly_runs() { cat stats_imapsync_${year}_${month}.runs } -echo statistics_VERSION_monthly 02 2012 +echo "statistics_VERSION_yearly_os 2012 # short" +statistics_VERSION_yearly_os() { + year=${1:-`date '+%Y'`} + ( + cd /home/lf/glamiral/imapsync_stats + Linux=`grep -i linux stats_imapsync_${year}.ip | wc -l` + Win32=`grep -i MSWin32 stats_imapsync_${year}.ip | wc -l` + Darwin=`grep -i darwin stats_imapsync_${year}.ip | wc -l` + FreeBSD=`grep -i freebsd stats_imapsync_${year}.ip | wc -l` + Solaris=`grep -i solaris stats_imapsync_${year}.ip | wc -l` + OpenBSD=`grep -i openbsd stats_imapsync_${year}.ip | wc -l` + Other=`egrep -i -v 'linux|MSWin32|darwin|freebsd|solaris|openbsd' stats_imapsync_${year}.ip |wc -l` + Nb_All=`cat stats_imapsync_${year}.ip | wc -l` + for OS in Linux Win32 Darwin FreeBSD Solaris OpenBSD Other; do + #echo $OS `eval "echo \\$$OS"` / $Nb_All + Nb_OS=`eval "echo \\$$OS"` + PerCent=`echo "scale=2; 100*$Nb_OS/$Nb_All" | bc -l` + echo $OS $PerCent % + done + ) +} + +echo +echo "statistics_VERSION_monthly 02 2012 # long, good choice" statistics_VERSION_monthly() { month=${1:-`date '+%m'`} year=${2:-`date '+%Y'`} @@ -131,38 +134,18 @@ statistics_VERSION_monthly() { } -echo statistics_VERSION_yearly_ip 2012 +echo "statistics_VERSION_yearly_ip 2012 # very long" statistics_VERSION_yearly_ip() { year=${1:-`date '+%Y'`} ( + statistics_VERSION_getstats cd /home/lf/glamiral/imapsync_stats cut -d ' ' -f 1,12,13,18,19 linux-france.org.??-??-${year}.imapsync_VERSION |sort -n |uniq -c|sort -n > stats_imapsync_${year}.ip ) } -echo statistics_VERSION_yearly_os 2012 -statistics_VERSION_yearly_os() { - year=${1:-`date '+%Y'`} - ( - cd /home/lf/glamiral/imapsync_stats - Linux=`grep linux stats_imapsync_${year}.ip | wc -l` - Win32=`grep MSWin32 stats_imapsync_${year}.ip | wc -l` - Darwin=`grep darwin stats_imapsync_${year}.ip | wc -l` - FreeBSD=`grep freebsd stats_imapsync_${year}.ip | wc -l` - Solaris=`grep solaris stats_imapsync_${year}.ip | wc -l` - OpenBSD=`grep openbsd stats_imapsync_${year}.ip | wc -l` - Nb_All=`cat stats_imapsync_${year}.ip | wc -l` - for OS in Linux Win32 Darwin FreeBSD Solaris OpenBSD; do - #echo $OS `eval "echo \\$$OS"` / $Nb_All - Nb_OS=`eval "echo \\$$OS"` - PerCent=`echo "scale=2; 100*$Nb_OS/$Nb_All" | bc -l` - echo $OS $PerCent % - done - ) -} - -echo statistics_VERSION_synthesis 2012 +echo "statistics_VERSION_synthesis 2012 # short" statistics_VERSION_synthesis() { year=${1:-`date '+%Y'`} ( @@ -177,6 +160,8 @@ statistics_VERSION_synthesis() { statistics_VERSION_yearly_os $year echo Biggest users tail -n 5 stats_imapsync_${year}.ip + echo -n "Nb runs each year : " + cat stats_imapsync_${year}.ip | awk '{ sum+=$1 } END {print sum}' ) } @@ -202,7 +187,7 @@ statistics_VERSION_getstats() { ) } -echo statistics_VERSION_monthly_ip 08 +echo "statistics_VERSION_monthly_ip 02 2012 # long" statistics_VERSION_monthly_ip() { month=${1:-`date '+%m'`} year=${2:-`date '+%Y'`} @@ -212,20 +197,21 @@ statistics_VERSION_monthly_ip() { ) } -echo statistics_VERSION_monthly_os 08 +echo "statistics_VERSION_monthly_os 08 2012 # short" statistics_VERSION_monthly_os() { month=${1:-`date '+%m'`} year=${2:-`date '+%Y'`} ( cd /home/imapsync/imapsync_stats - Linux=`grep linux stats_imapsync_${year}_${month}.ip | wc -l` - Win32=`grep MSWin32 stats_imapsync_${year}_${month}.ip | wc -l` - Darwin=`grep darwin stats_imapsync_${year}_${month}.ip | wc -l` - FreeBSD=`grep freebsd stats_imapsync_${year}_${month}.ip | wc -l` - Solaris=`grep solaris stats_imapsync_${year}_${month}.ip | wc -l` - OpenBSD=`grep openbsd stats_imapsync_${year}_${month}.ip | wc -l` - Nb_All=`cat stats_imapsync_${year}_${month}.ip | wc -l ` - for OS in Linux Win32 Darwin FreeBSD Solaris OpenBSD; do + Linux=`grep -i linux stats_imapsync_${year}_${month}.ip | wc -l` + Win32=`grep -i MSWin32 stats_imapsync_${year}_${month}.ip | wc -l` + Darwin=`grep -i darwin stats_imapsync_${year}_${month}.ip | wc -l` + FreeBSD=`grep -i freebsd stats_imapsync_${year}_${month}.ip | wc -l` + Solaris=`grep -i solaris stats_imapsync_${year}_${month}.ip | wc -l` + OpenBSD=`grep -i openbsd stats_imapsync_${year}_${month}.ip | wc -l` + Other=`egrep -i -v 'linux|MSWin32|darwin|freebsd|solaris|openbsd' stats_imapsync_${year}.ip |wc -l` + Nb_All=`cat stats_imapsync_${year}.ip | wc -l` + for OS in Linux Win32 Darwin FreeBSD Solaris OpenBSD Other; do #echo $OS `eval "echo \\$$OS"` / $Nb_All Nb_OS=`eval "echo \\$$OS"` PerCent=`echo "scale=2; 100*$Nb_OS/$Nb_All" | bc -l` @@ -234,19 +220,20 @@ statistics_VERSION_monthly_os() { ) } -echo statistics_VERSION_yearly_os +echo "statistics_VERSION_yearly_os 2012 # short" statistics_VERSION_yearly_os() { year=${1:-`date '+%Y'`} ( cd /home/imapsync/imapsync_stats - Linux=`grep linux stats_imapsync_${year}.ip | wc -l` - Win32=`grep MSWin32 stats_imapsync_${year}.ip | wc -l` - Darwin=`grep darwin stats_imapsync_${year}.ip | wc -l` - FreeBSD=`grep freebsd stats_imapsync_${year}.ip | wc -l` - Solaris=`grep solaris stats_imapsync_${year}.ip | wc -l` - OpenBSD=`grep openbsd stats_imapsync_${year}.ip | wc -l` + Linux=`grep -i linux stats_imapsync_${year}.ip | wc -l` + Win32=`grep -i MSWin32 stats_imapsync_${year}.ip | wc -l` + Darwin=`grep -i darwin stats_imapsync_${year}.ip | wc -l` + FreeBSD=`grep -i freebsd stats_imapsync_${year}.ip | wc -l` + Solaris=`grep -i solaris stats_imapsync_${year}.ip | wc -l` + OpenBSD=`grep -i openbsd stats_imapsync_${year}.ip | wc -l` + Other=`egrep -i -v 'linux|MSWin32|darwin|freebsd|solaris|openbsd' stats_imapsync_${year}.ip |wc -l` Nb_All=`cat stats_imapsync_${year}.ip | wc -l` - for OS in Linux Win32 Darwin FreeBSD Solaris OpenBSD; do + for OS in Linux Win32 Darwin FreeBSD Solaris OpenBSD Other; do #echo $OS `eval "echo \\$$OS"` / $Nb_All Nb_OS=`eval "echo \\$$OS"` PerCent=`echo "scale=2; 100*$Nb_OS/$Nb_All" | bc -l` @@ -256,18 +243,7 @@ statistics_VERSION_yearly_os() { } - - -echo statistics_VERSION_yearly_ip -statistics_VERSION_yearly_ip() { - year=${1:-`date '+%Y'`} - ( - cd /home/imapsync/imapsync_stats - cut -d ' ' -f 1,12,13,18,19 access.log_${year}????.imapsync_VERSION |sort -n |uniq -c|sort -n > stats_imapsync_${year}.ip - ) -} - -echo statistics_VERSION_monthly_ip_wc 01 2012 +echo "statistics_VERSION_monthly_ip_wc 02 2012 # short" statistics_VERSION_monthly_ip_wc() { month=${1:-`date '+%m'`} year=${2:-`date '+%Y'`} @@ -278,7 +254,7 @@ statistics_VERSION_monthly_ip_wc() { ) } -echo statistics_VERSION_monthly_runs 01 2012 +echo "statistics_VERSION_monthly_runs 02 2012 # short" statistics_VERSION_monthly_runs() { month=${1:-`date '+%m'`} year=${2:-`date '+%Y'`} @@ -289,7 +265,8 @@ statistics_VERSION_monthly_runs() { ) } -echo statistics_VERSION_monthly 01 2012 +echo +echo "statistics_VERSION_monthly 02 2012 # long, good choice" statistics_VERSION_monthly() { month=${1:-`date '+%m'`} year=${2:-`date '+%Y'`} @@ -301,7 +278,18 @@ statistics_VERSION_monthly() { ) } -echo statistics_VERSION_synthesis 2012 + +echo "statistics_VERSION_yearly_ip 2012 # very long" +statistics_VERSION_yearly_ip() { + year=${1:-`date '+%Y'`} + ( + statistics_VERSION_getstats + cd /home/imapsync/imapsync_stats + cut -d ' ' -f 1,12,13,18,19 access.log_${year}????.imapsync_VERSION |sort -n |uniq -c|sort -n > stats_imapsync_${year}.ip + ) +} + +echo "statistics_VERSION_synthesis 2012 # short" statistics_VERSION_synthesis() { year=${1:-`date '+%Y'`} ( @@ -316,8 +304,14 @@ statistics_VERSION_synthesis() { statistics_VERSION_yearly_os $year echo Biggest users tail -n 5 stats_imapsync_${year}.ip + echo -n "Nb runs each year : " + cat stats_imapsync_${year}.ip | awk '{ sum+=$1 } END {print sum}' ) } + + + + } diff --git a/W/paypal_reply/memo b/W/paypal_reply/memo index c62e4e8..a34e96d 100644 --- a/W/paypal_reply/memo +++ b/W/paypal_reply/memo @@ -28,18 +28,40 @@ Europe a un autre assujetti : Article 262 ter => Exoneration EOF } -echo paypal_bilan_Avant_commission -paypal_bilan_Avant_commission() { -# DID output diff between paypal_bilan_1.60 and 1.61 + +echo paypal_bilan_invoice_00000 +paypal_bilan_invoice_00000() { +# DID output diff between paypal_bilan_1.62 and 1.63 ( #set -x -/g/public_html/imapsync/W/paypal_reply/paypal_bilan_1.60 --bnc --debug --debug_invoice --first_in 147 \ - --avoid_numbers '292 293 643 644 731 732 1093 1330 1331 1332 1333 1334 1652 1653' \ +/g/public_html/imapsync/W/paypal_reply/paypal_bilan_1.62 --bnc --debug --debug_invoice --first_in 147 \ + --avoid_numbers '292 293 643 644 731 732 1093 1330 1331 1332 1333 1334 1652 1653 2131 2132' \ + /g/paypal/paypal_201?_??_complet.csv \ + > /g/var/paypal_bilan/tests/paypal_invoice.out1 2>&1 + +/g/public_html/imapsync/W/paypal_reply/paypal_bilan --dry --write_invoices --exportbnc paypal_bnc.txt --bnc --debug --debug_invoice --first_in 147 \ + --avoid_numbers '292 293 643 644 731 732 1093 1330 1331 1332 1333 1334 1652 1653 2131 2132' \ + /g/paypal/paypal_201?_??_complet.csv \ + > /g/var/paypal_bilan/tests/paypal_invoice.out2 2>&1 + +echo diff /g/var/paypal_bilan/tests/paypal_invoice.out1 /g/var/paypal_bilan/tests/paypal_invoice.out2 + diff /g/var/paypal_bilan/tests/paypal_invoice.out1 /g/var/paypal_bilan/tests/paypal_invoice.out2 +) +} + + +#echo paypal_bilan_Avant_commission +paypal_bilan_Avant_commission() { +# DID output diff between paypal_bilan_1.61 and 1.62 +( +#set -x +/g/public_html/imapsync/W/paypal_reply/paypal_bilan_1.61 --bnc --debug --debug_invoice --first_in 147 \ + --avoid_numbers '292 293 643 644 731 732 1093 1330 1331 1332 1333 1334 1652 1653 2131 2132' \ /g/paypal/paypal_201?_??_complet.csv \ > /g/var/paypal_bilan/tests/paypal_invoice.out1 2>&1 /g/public_html/imapsync/W/paypal_reply/paypal_bilan --exportbnc paypal_bnc.txt --bnc --debug --debug_invoice --first_in 147 \ - --avoid_numbers '292 293 643 644 731 732 1093 1330 1331 1332 1333 1334 1652 1653' \ + --avoid_numbers '292 293 643 644 731 732 1093 1330 1331 1332 1333 1334 1652 1653 2131 2132' \ /g/paypal/paypal_201?_??_complet.csv \ > /g/var/paypal_bilan/tests/paypal_invoice.out2 2>&1 diff --git a/W/paypal_reply/paypal_bilan b/W/paypal_reply/paypal_bilan index 4cc355e..25366e9 100755 --- a/W/paypal_reply/paypal_bilan +++ b/W/paypal_reply/paypal_bilan @@ -1,6 +1,6 @@ #!/usr/bin/perl -# $Id: paypal_bilan,v 1.61 2012/11/02 01:31:58 gilles Exp gilles $ +# $Id: paypal_bilan,v 1.62 2012/12/06 18:45:02 gilles Exp gilles $ use strict; use warnings; @@ -13,7 +13,7 @@ use Test::More 'no_plan' ; die unless (utf8_supported_charset('ISO-8859-1')); -my $rcs = '$Id: paypal_bilan,v 1.61 2012/11/02 01:31:58 gilles Exp gilles $ ' ; +my $rcs = '$Id: paypal_bilan,v 1.62 2012/12/06 18:45:02 gilles Exp gilles $ ' ; $rcs =~ m/,v (\d+\.\d+)/ ; my $VERSION = ($1) ? $1: "UNKNOWN" ; @@ -35,6 +35,7 @@ my $nb_invoice_suspended = 0 ; my $nb_invoice_canceled = 0 ; my ( $tests, $testeur ) ; +my $dry ; my $debug ; my $debug_csv ; my $debug_dev ; @@ -58,6 +59,7 @@ my $dir_invoices = '/g/var/paypal_invoices' ; my $option_ret = GetOptions ( 'tests' => \$tests, + 'dry' => \$dry, 'debug' => \$debug, 'debug_csv' => \$debug_csv, 'debug_dev' => \$debug_dev, @@ -342,6 +344,19 @@ sub keyval { } +sub invoice_00000 { + my $invoice = shift ; + + return( sprintf( "%04d", $invoice ) ) ; +} + +sub tests_invoice_00000 { + + ok( '0000' eq invoice_00000( 0 ), 'invoice_00000: 0 -> 0000' ) ; + ok( '0147' eq invoice_00000( 147 ), 'invoice_00000: 147 -> 0147' ) ; + ok( '99999' eq invoice_00000( 99999 ), 'invoice_00000: 99999 -> 99999' ) ; +} + sub tests_next_invoice { ok( 1 == next_invoice( ), 'next_invoice: 1' ) ; ok( 2 == next_invoice( ), 'next_invoice: 2' ) ; @@ -359,6 +374,7 @@ sub tests { tests_next_invoice( ) ; #tests_half( ) ; tests_cut( ) ; + tests_invoice_00000( ) ; } sub compute_line { @@ -659,8 +675,8 @@ sub build_invoice { my $tex_variables_utf8 = to_utf8( { -string => $tex_variables, -charset => 'ISO-8859-1' } ) ; - print $tex_variables_utf8 if $debug_invoice_utf8 ; - print $tex_variables if $debug_invoice ; + $debug_invoice_utf8 and print $tex_variables_utf8 ; + $debug_invoice and print $tex_variables ; #print "$invoice ", invoice_sent( $dir_invoices, $invoice, $De_l_adresse_email ), "\n" ; if ( $write_invoices and ! invoice_sent( $dir_invoices, $invoice, $De_l_adresse_email ) ) { @@ -849,7 +865,11 @@ sub write_csv_info { my( $dir_invoices, $invoice, $file_csv, $line_number, $line_csv ) = @_ ; - open( CSVINFO, "> $dir_invoices/$invoice/csv_info.txt") or die ; + my $invoice_00000 = invoice_00000( $invoice ) ; + $debug and print "Writing $dir_invoices/$invoice_00000/csv_info.txt\n" ; + $dry and return( ) ; + + open( CSVINFO, "> $dir_invoices/$invoice_00000/csv_info.txt") or die ; print CSVINFO join( "\n", $file_csv, $line_number, $line_csv ) ; close( CSVINFO ) ; @@ -858,8 +878,8 @@ sub write_csv_info { sub invoice_sent { my ( $dir_invoices, $invoice, $email_address ) = @_ ; - - return( 1 ) if ( -f "$dir_invoices/$invoice/SENT_TO_$email_address" ) ; + my $invoice_00000 = invoice_00000( $invoice ) ; + return( 1 ) if ( -f "$dir_invoices/$invoice_00000/SENT_TO_$email_address" ) ; return( 0 ) ; } @@ -869,17 +889,24 @@ sub write_email_message { my $message_body_utf8 = to_utf8({ -string => $message_body, -charset => 'ISO-8859-1' }); - mkdir( "$dir_invoices/$invoice" ) or die if ! -d "$dir_invoices/$invoice" ; - - open( HEADER, "> $dir_invoices/$invoice/facture_message_header.txt") or die ; + my $invoice_00000 = invoice_00000( $invoice ) ; + + if ( ! -d "$dir_invoices/$invoice_00000" ) { + $debug and print "mkdir $dir_invoices/$invoice_00000\n" ; + $dry or mkdir( "$dir_invoices/$invoice_00000" ) or die ; + } + + $dry and return( ) ; + + open( HEADER, "> $dir_invoices/$invoice_00000/facture_message_header.txt") or die ; print HEADER $message_header ; close( HEADER ) ; - open( BODY, "> $dir_invoices/$invoice/facture_message_body.txt") or die ; + open( BODY, "> $dir_invoices/$invoice_00000/facture_message_body.txt") or die ; print BODY $message_body_utf8 ; close( BODY ) ; - open( ADDRESS, "> $dir_invoices/$invoice/email_address.txt") or die ; + open( ADDRESS, "> $dir_invoices/$invoice_00000/email_address.txt") or die ; print ADDRESS "$email_address\n" ; close( ADDRESS ) ; } @@ -888,14 +915,23 @@ sub write_email_message { sub write_tex_variables_file { my ( $dir_invoices, $invoice, $date_jjSmmSaaaa, $tex_variables_utf8 ) = @_ ; - mkdir( "$dir_invoices/$invoice" ) or die if ! -d "$dir_invoices/$invoice" ; - open( FILE, "> $dir_invoices/$invoice/imapsync_var.tex") or die ; + my $invoice_00000 = invoice_00000( $invoice ) ; + + if ( ! -d "$dir_invoices/$invoice_00000" ) { + $debug and print "mkdir $dir_invoices/$invoice_00000\n" ; + $dry or mkdir( "$dir_invoices/$invoice_00000" ) or die ; + } + + $debug and print "Writing imapsync_var.tex $dir_invoices/$invoice_00000/imapsync_var.tex\n" ; + $dry and return( ) ; + + open( FILE, "> $dir_invoices/$invoice_00000/imapsync_var.tex") or die ; print FILE $tex_variables_utf8 ; close( FILE ) ; - if ( ! -f "$dir_invoices/$invoice/imapsync_var_manual.tex" ) { - open( FILE, "> $dir_invoices/$invoice/imapsync_var_manual.tex") or die ; - print FILE "%% $0 created file + if ( ! -f "$dir_invoices/$invoice_00000/imapsync_var_manual.tex" ) { + open( FILE, "> $dir_invoices/$invoice_00000/imapsync_var_manual.tex") or die ; + print FILE "%% $0 created this file %% Can be used to override imapsync_var.tex definitions\n" ; print FILE $tex_variables_utf8 ; close( FILE ) ; diff --git a/W/paypal_reply/paypal_bilan_1.61 b/W/paypal_reply/paypal_bilan_1.61 new file mode 100755 index 0000000..4cc355e --- /dev/null +++ b/W/paypal_reply/paypal_bilan_1.61 @@ -0,0 +1,1171 @@ +#!/usr/bin/perl + +# $Id: paypal_bilan,v 1.61 2012/11/02 01:31:58 gilles Exp gilles $ + +use strict; +use warnings; +use Getopt::Long; +use Text::CSV_XS ; +use IO::Handle ; +use Data::Dumper ; +use Unicode::MapUTF8 qw(to_utf8 from_utf8 utf8_supported_charset); +use Test::More 'no_plan' ; + +die unless (utf8_supported_charset('ISO-8859-1')); + +my $rcs = '$Id: paypal_bilan,v 1.61 2012/11/02 01:31:58 gilles Exp gilles $ ' ; +$rcs =~ m/,v (\d+\.\d+)/ ; +my $VERSION = ($1) ? $1: "UNKNOWN" ; + + +my $total_usd_received = 0 ; +my $total_usd_invoice = 0 ; +my $total_HT_EUR_exo = 0 ; +my $total_HT_EUR_ass = 0 ; +my $total_TVA_EUR = 0 ; + +my $total_HT_EUR_sup = 0 ; +my $total_TVA_EUR_sup = 0 ; + +my $total_eur_received = 0 ; +my $total_eur_invoice = 0 ; +my $nb_invoice = 0 ; +my $nb_invoice_refund = 0 ; +my $nb_invoice_suspended = 0 ; +my $nb_invoice_canceled = 0 ; + +my ( $tests, $testeur ) ; +my $debug ; +my $debug_csv ; +my $debug_dev ; +my $debug_invoice ; +my $debug_invoice_utf8 ; + +my $first_invoice = 1 ; +my $print_details = '' ; +my $bnc = '' ; +my $exportbnc = '' ; + +my $usdeur = 1.2981 ; +my $invoices ; +my %invoice_refund ; +my %invoice_canceled ; +my %invoice_suspended ; +my $write_invoices = 0 ; +my $avoid_numbers ; + +my $dir_invoices = '/g/var/paypal_invoices' ; + +my $option_ret = GetOptions ( + 'tests' => \$tests, + 'debug' => \$debug, + 'debug_csv' => \$debug_csv, + 'debug_dev' => \$debug_dev, + 'debug_invoice' => \$debug_invoice, + 'debug_invoice_utf8' => \$debug_invoice_utf8, + + 'first_invoice=i' => \$first_invoice, + 'print_details|details' => \$print_details, + 'bnc' => \$bnc, + 'exportbnc=s' => \$exportbnc, + 'usdeur=f' => \$usdeur, + 'invoices=s' => \$invoices, + 'write_invoices!' => \$write_invoices, + 'avoid_numbers=s' => \$avoid_numbers, +); + +$testeur = Test::More->builder ; +$testeur->no_ending(1) ; + +if ( $tests ) { + $testeur->no_ending( 0 ) ; + exit( tests( ) ) ; +} + + +my @files = @ARGV ; +my %action_of_invoice ; + +my %invoice_paypal ; +#$invoice_paypal{ $first_invoice } = 1 ; + +my @invoices_wanted = split( /\s+/, $invoices ) if $invoices ; + +my @avoid_numbers = split( /\s+/, $avoid_numbers ) if $avoid_numbers ; +my %avoid_numbers ; +@avoid_numbers{ @avoid_numbers } = ( ) if @avoid_numbers ; + +#print "@invoices\n" ; + +foreach my $file ( @files ) { + + my @actions = parse_file( $file ) ; + + foreach my $action (@actions) { + my %action = %$action ; + #print $action->{ Nom }, "\n" ; + my( $Date, $Heure, $Fuseau_horaire, $Nom, $Type, $Etat, + $Devise, $Montant, $Numero_davis_de_reception, $Solde, + $Pays, $Nom_Option_1, $Valeur_Option_1, $Hors_taxe, $Titre_de_l_objet, $Nom_Option_2, $Option_2_Valeur ) + = @action{ ( 'Date', 'Heure', 'Fuseau horaire', 'Nom', 'Type', 'Etat', + 'Devise', 'Montant', "Numéro d'avis de réception", 'Solde', + 'Pays', 'Nom Option 1', 'Valeur Option 1', 'Hors taxe', "Titre de l'objet", 'Nom Option 2', 'Option 2 Valeur') } ; + #print "$Nom\n" ; + ( $Etat ) = @action{ ( 'Etat' ) } || @action{ ( 'État' ) } ; + ( $Hors_taxe ) = @action{ ( 'Hors taxe' ) } || @action{ ( 'Avant commission' ) } ; + my $invoice = 'NONE' ; + $Montant = $action->{ Net } if not defined $Montant; + compute_line($action, $invoice, $Date, $Heure, $Fuseau_horaire, $Nom, $Type, $Etat, + $Devise, $Montant, $Numero_davis_de_reception, $Solde, + $Pays, $Nom_Option_1, $Valeur_Option_1, $Hors_taxe, $Titre_de_l_objet ) ; + + # index by invoice number + $action_of_invoice{ $action->{ 'invoice' } } = $action ; + } + delete $action_of_invoice{ 'NONE' } ; +} + +my $last_invoice ; +my @invoice_paypal = sort { $a <=> $b } keys %invoice_paypal ; +$last_invoice = $invoice_paypal[-1] || 0 ; +my $first_invoice_paypal = $invoice_paypal[0] || 0 ; + +@invoices_wanted = ( $first_invoice .. $last_invoice ) if ( ! @invoices_wanted ) ; + +my @invoice_sent ; +my %invoice_sent ; +my @invoice_not_sent ; +my %invoice_not_sent ; + +foreach my $invoice ( @invoices_wanted ) { + + my $action = $action_of_invoice{ $invoice } ; + next if ! $action ; + my $email_address = $action->{ "De l'adresse email" } ; + + my $invoice_sent = invoice_sent( $dir_invoices, $invoice, $email_address ) ; + #print "$invoice $invoice_sent\n" ; + + if ( $invoice_sent ) { + $invoice_sent{ $invoice }++ ; + #build_invoice( $invoice ) ; + }elsif( not ( $invoice_canceled{ $invoice } or $invoice_refund{ $invoice } ) ) { + $invoice_not_sent{ $invoice }++ ; + build_invoice( $invoice ) ; + } +} + +@invoice_sent = sort { $a <=> $b } keys( %invoice_sent ) ; +my $nb_invoice_sent = scalar( @invoice_sent ) ; +@invoice_not_sent = sort { $a <=> $b } keys( %invoice_not_sent ) ; + +my @invoice_canceled = sort { $a <=> $b } keys( %invoice_canceled ) ; +my @invoice_suspended = sort { $a <=> $b } keys( %invoice_suspended ) ; +my @invoice_refund = sort { $a <=> $b } keys( %invoice_refund ) ; + + +print( "\n", "=" x 60, "\n" ) if $bnc ; + + + +print "USD banque $total_usd_received\n" ; +print "USD invoice $total_usd_invoice\n" ; +my $total_eur_from_usd ; +$total_eur_from_usd = sprintf('%2.2f', $total_usd_invoice / $usdeur ) ; # au 30 nov 2010 http://fr.finance.yahoo.com/devises/convertisseur/#from=EUR;to=USD;amt=1 +print "EUR from USD $total_eur_from_usd\n" ; +print "EUR banque $total_eur_received\n" ; +print "EUR invoice $total_eur_invoice\n" ; + +my $total_eur = $total_eur_from_usd + $total_eur_invoice ; + +$total_HT_EUR_exo = sprintf('%2.2f', $total_HT_EUR_exo) ; +$total_HT_EUR_ass = sprintf('%2.2f', $total_HT_EUR_ass) ; +$total_TVA_EUR = sprintf('%2.2f', $total_TVA_EUR) ; + +$total_HT_EUR_sup = sprintf('%2.2f', $total_HT_EUR_sup) ; +$total_TVA_EUR_sup = sprintf('%2.2f', $total_TVA_EUR_sup) ; + +$total_eur = sprintf('%2.2f', $total_eur) ; + +print "EUR total $total_eur\n" ; +print "EUR total HT exo $total_HT_EUR_exo\n" ; +print "EUR total HT assuj $total_HT_EUR_ass\n" ; +print "EUR total TVA $total_TVA_EUR\n" ; +print "EUR total HT sup $total_HT_EUR_sup\n" ; +print "EUR total TVA sup $total_TVA_EUR_sup\n" ; +print "Nb invoice $nb_invoice ( from $first_invoice_paypal to $last_invoice )\n" ; +print "Nb invoice canceled ($nb_invoice_canceled) @invoice_canceled\n" ; +print "Nb invoice suspended ($nb_invoice_suspended) @invoice_suspended\n" ; +print "Nb invoice refund ($nb_invoice_refund) @invoice_refund\n" ; +print "Nb invoice sent $nb_invoice_sent\n" ; +print "Have to send invoices @invoice_not_sent\n" if ( @invoice_not_sent ) ; + +my $total_eur2 = $total_HT_EUR_exo + $total_HT_EUR_ass + $total_TVA_EUR + $total_HT_EUR_sup + $total_TVA_EUR_sup ; +$total_eur2 = sprintf('%2.2f', $total_eur2) ; +print "$total_eur != $total_eur2 = $total_HT_EUR_exo + $total_HT_EUR_ass + $total_TVA_EUR + $total_HT_EUR_sup + $total_TVA_EUR_sup\n" +if ( $total_eur != $total_eur2 ) ; + +sub parse_one_line_io { + my $csv = shift ; + my $io = shift ; + + my $line = $csv->getline($io) ; + + return if ( $csv->eof( ) ) ; + if ( not defined( $line ) ) { + my($cde, $str, $pos) = $csv->error_diag () ; + print "[$cde] [$str] [$pos]\n" ; + + } + return( $line ) ; +} + +sub hash_and_count_dupplicate { + my @columns = @_ ; + my %columns ; + + #@columns_def{ @columns_def } = ( ) ; + foreach my $col ( @columns ) { + $columns{ $col } += 1 ; + } + $debug_csv and print "Nb columns: ", scalar( keys %columns ), " ", scalar( @columns ), "\n" ; + # debug how many time a title is defined + foreach my $col (1 .. scalar( @columns )) { + $debug_csv and print "$col | ", + deci_to_AA( $col ) , " | ", + $columns{ $columns[ $col - 1 ] }, " | ", + $columns[ $col - 1 ], "\n" ; + } + + # exit in case two columns have the same name + die "Erreur : doublons dans les titres\n" if ( scalar( keys %columns ) != scalar( @columns ) ) ; + + return( %columns ) ; +} + +sub deci_to_AA { + my $deci = shift ; + my $AA = ''; + + while ( $deci > 0 ) { + my $quot = int( ( $deci - 1 ) / 26 ) ; + my $rest = $deci - 1 - ( 26 * $quot ) ; + my $char = chr ( ord('A') + $rest ) ; + $AA = $char . $AA ; + $deci = $quot ; + } + #print "col=$AA\n" ; + return( $AA ) ; +} + +sub remove_first_blank { + my $string = shift ; + + $string =~ s/^ +// ; + return( $string ) ; + +} + +sub parse_file { + my $file = shift ; + + open my $io, "<", $file or die "$file: $!" ; + + my $csv = Text::CSV_XS->new( { + sep_char => ',', + binary => 1, + keep_meta_info => 1, + eol => $/, + } ) ; + + my $line_1 = parse_one_line_io( $csv, $io ) ; + die if ( not defined $line_1 ) ; # first line must have no problem + + my @columns_def_orig = @$line_1 ; + my @columns_def = map { remove_first_blank( $_ ) } @columns_def_orig ; + $debug_csv and print "columns_def = ", map( { "[$_]" } @columns_def ), "\n"; + + my %columns_def = hash_and_count_dupplicate( @columns_def ) ; + my $nb_columns_def = scalar @columns_def ; + + my $line_counter = 2 ; + my @actions ; + while ( 1 ) { + $debug_csv and print "ligne $line_counter ", $csv->eof( ), "\n" ; + my $line = parse_one_line_io( $csv, $io ) ; + last if ( $csv->eof( ) ) ; + if ( not defined $line ) { + print "Erreur ligne $line_counter : ", $csv->error_diag, "\n\n"; + ++$line_counter ; + next ; + } + my @columns = @$line ; + + if ( $nb_columns_def != scalar @columns ) { + print "Erreur ligne $line_counter : nombre de colonnes = ", scalar @columns, " != $nb_columns_def\n" ; + ++$line_counter ; + next ; + } + my %columns ; + @columns{ @columns_def } = @columns ; + $columns{ 'file_csv' } = $file ; + $columns{ 'line_number' } = $line_counter ; + $csv->combine( @columns ) ; + my $line_csv = $csv->string(); + $columns{ 'line_csv' } = $line_csv ; + $debug_csv and print map( { "[$_] = [" . $columns{$_} . "]\n" } + @columns_def, 'line_number', 'line_csv', 'file_csv' ), + "\n"; + ++$line_counter ; + push( @actions, \%columns ) ; + } + close( $io ); + return( reverse @actions ) ; +} + +sub next_invoice { + my @current_numbers = sort { $a <=> $b } ( $first_invoice - 1, keys( %invoice_paypal ) ) ; + my $last_invoice = $current_numbers[ -1 ] || 0 ; + + #keys( %avoid_numbers ), + my $next_invoice = $last_invoice + 1 ; + while ( exists( $avoid_numbers{ $next_invoice } ) ) { $next_invoice++ ; } + $invoice_paypal{ $next_invoice } = 1 ; + #print "AAA [@current_numbers] [$last_invoice] [$next_invoice]\n" ; + + return( $next_invoice ) ; +} + +sub keyval { + my %hash = @_ ; + return( join( " ", map( { "$_ => " . $hash{ $_ } } keys %hash ) ) . "\n" ) ; +} + + +sub tests_next_invoice { + ok( 1 == next_invoice( ), 'next_invoice: 1' ) ; + ok( 2 == next_invoice( ), 'next_invoice: 2' ) ; + @avoid_numbers{ (3, 4, 6, 8 ) } = ( ) ; + ok( 5 == next_invoice( ), 'next_invoice: 7' ) ; + ok( 7 == next_invoice( ), 'next_invoice: 8' ) ; + ok( 9 == next_invoice( ), 'next_invoice: 9' ) ; + %invoice_paypal = () ; + $first_invoice = 7 ; + ok( 7 == next_invoice( ), 'next_invoice: 7' ) ; +} + + +sub tests { + tests_next_invoice( ) ; + #tests_half( ) ; + tests_cut( ) ; +} + +sub compute_line { + my( $action, $invoice, $Date, $Heure, $Fuseau_horaire, $Nom, $Type, $Etat, + $Devise, $Montant, $Numero_davis_de_reception, $Solde, + $Pays, $Nom_Option_1, $Valeur_Option_1, $Hors_taxe_paypal, $Titre_de_l_objet ) = @_ ; + + $debug and print( "-" x 60, "\n", + "[$Date] [$Heure] [$Fuseau_horaire] [$Nom] [$Type] [$Etat] ", + "[$Devise] [$Hors_taxe_paypal] [$Montant] [$Numero_davis_de_reception] [$Solde]\n", + "[$Pays] [$Nom_Option_1] [$Valeur_Option_1] [$Titre_de_l_objet]\n" ) ; + + $Montant =~ s/[^0-9-,.]//g ; + $Montant =~ s/,/./g ; + #$debug and print "MM[$Montant]\n" ; + $Hors_taxe_paypal =~ s/,/./g ; + + my $MontantEUR; + my( $montant_HT_EUR_exo, $montant_HT_EUR_ass, $montant_TVA_EUR ) ; + my( $montant_HT_EUR_sup, $montant_TVA_EUR_sup ) ; + + if ( $bnc ) { + $MontantEUR = $Montant ; + $MontantEUR = sprintf( "%.4f", $Montant/$usdeur ) if ($Devise eq 'USD') ; + print( "\n", "=" x 60, "\n" ) ; + print( "[$Date] [$Nom] [$Type] [$Etat] [$Devise] [$Hors_taxe_paypal] [$Montant] [EUR $MontantEUR]\n", + "[$Pays] [$Nom_Option_1] [$Valeur_Option_1] [$Titre_de_l_objet]\n" ) ; + } + + if ( + 'Paiement sur site marchand reçu' eq $Type + and 'USD' eq $Devise + and ( 'Terminé' eq $Etat or 'Compensé' eq $Etat ) + ) { + $Montant =~tr/,/./; + #print "$Montant\n" ; + my $Montant2_usd; + $Montant2_usd = $Hors_taxe_paypal ; + $total_usd_received += $Montant ; + $total_usd_invoice += $Montant2_usd ; + ( $montant_HT_EUR_exo, $montant_HT_EUR_ass, $montant_TVA_EUR, $montant_HT_EUR_sup, $montant_TVA_EUR_sup ) + = tva_line( $Devise, $Montant2_usd, $Pays, $Nom_Option_1, $Valeur_Option_1, $Titre_de_l_objet ) ; + $total_HT_EUR_exo += $montant_HT_EUR_exo ; + $total_HT_EUR_ass += $montant_HT_EUR_ass ; + $total_TVA_EUR += $montant_TVA_EUR ; + #$invoice = $first_invoice + $nb_invoice ; + $invoice = next_invoice( ) ; + $nb_invoice++ ; + $print_details and print ( "[$invoice] [$Date] [$Heure] [$Fuseau_horaire] [$Nom] [$Type] [$Etat] [$Devise] [$Montant] [$Numero_davis_de_reception] [$Solde]\n" ) ; + + } + + if ( + 'Paiement sur site marchand reçu' eq $Type + and 'EUR' eq $Devise + and ( 'Terminé' eq $Etat or 'Compensé' eq $Etat ) + ) { + $Montant =~tr/,/./; + #print "$Montant\n" ; + my $Montant2_eur; + $Montant2_eur = $Hors_taxe_paypal ; + $total_eur_received += $Montant ; + $total_eur_invoice += $Montant2_eur ; + ( $montant_HT_EUR_exo, $montant_HT_EUR_ass, $montant_TVA_EUR, $montant_HT_EUR_sup, $montant_TVA_EUR_sup ) + = tva_line( $Devise, $Montant2_eur, $Pays, $Nom_Option_1, $Valeur_Option_1, $Titre_de_l_objet ) ; + $total_HT_EUR_exo += $montant_HT_EUR_exo ; + $total_HT_EUR_ass += $montant_HT_EUR_ass ; + $total_TVA_EUR += $montant_TVA_EUR ; + $total_HT_EUR_sup += $montant_HT_EUR_sup ; + $total_TVA_EUR_sup += $montant_TVA_EUR_sup ; + + + #$invoice = $first_invoice + $nb_invoice ; + $invoice = next_invoice( ) ; + $nb_invoice++ ; + $print_details and print ( "[$invoice] [$Date] [$Heure] [$Fuseau_horaire] [$Nom] [$Type] [$Etat] [$Devise] [$Montant] [$Numero_davis_de_reception] [$Solde]\n" ) ; + } + + if ( + 'Paiement sur site marchand reçu' eq $Type + and 'EUR' eq $Devise + and 'Remboursé' eq $Etat + ) { + $invoice = next_invoice( ) ; + $nb_invoice++ ; + $nb_invoice_refund++; + $invoice_refund{ $invoice }++ ; + + $print_details and print ( "[$invoice] [$Date] [$Heure] [$Fuseau_horaire] [$Nom] [$Type] [$Etat] [$Devise] [$Montant] [$Numero_davis_de_reception] [$Solde]\n" ) ; + } + + if ( + 'Paiement sur site marchand reçu' eq $Type + and 'EUR' eq $Devise + and 'Annulé' eq $Etat + ) { + $invoice = next_invoice( ) ; + $nb_invoice++ ; + $nb_invoice_canceled++; + $invoice_canceled{ $invoice }++ ; + + $print_details and print ( "[$invoice] [$Date] [$Heure] [$Fuseau_horaire] [$Nom] [$Type] [$Etat] [$Devise] [$Montant] [$Numero_davis_de_reception] [$Solde]\n" ) ; + } + + if ( + 'Paiement sur site marchand reçu' eq $Type + and 'EUR' eq $Devise + and 'Suspendu' eq $Etat + ) { + $invoice = next_invoice( ) ; + $nb_invoice++ ; + $nb_invoice_suspended++; + $invoice_suspended{ $invoice }++ ; + + $print_details and print ( "[$invoice] [$Date] [$Heure] [$Fuseau_horaire] [$Nom] [$Type] [$Etat] [$Devise] [$Montant] [$Numero_davis_de_reception] [$Solde]\n" ) ; + } + + if ( + 'Paiement sur site marchand reçu' eq $Type + and 'EUR' eq $Devise + and 'Non compensé' eq $Etat + ) { + $invoice = next_invoice( ) ; + $nb_invoice++ ; + $print_details and print ( "[$invoice] [$Date] [$Heure] [$Fuseau_horaire] [$Nom] [$Type] [$Etat] [$Devise] [$Montant] [$Numero_davis_de_reception] [$Solde]\n" ) ; + } + + $action->{ 'invoice' } = $invoice ; + if ( $bnc ) { + my $FR_flag = '' ; + $FR_flag = ' FR' if $Pays eq 'France' ; + my $IND_flag = '' ; + $IND_flag = ' IND' if ('imapsync usage' eq $Nom_Option_1 and 'individual' eq $Valeur_Option_1 ) ; + my $SUPPORT_flag = '' ; + $SUPPORT_flag = ' support' if ( 'imapsync support' eq $Titre_de_l_objet ) ; + #print "FE $invoice$FR_flag$IND_flag\n" ; + #printf( "%.2f [EUR %.2f]\n", $Montant, $MontantEUR ) ; + print "FE $invoice$FR_flag$IND_flag imapsync$SUPPORT_flag $Nom\n" ; + print "[$Date]$FR_flag$IND_flag $MontantEUR $Devise \n" ; + } +} + +sub build_invoice { + my $invoice = shift ; + + return if ! $invoice ; + + my $action = $action_of_invoice{ $invoice } ; + my $refund = '' ; + $refund = 'REFUND ' if $invoice_refund{ $invoice } ; + my %action = %$action if $action ; + #print Data::Dumper->Dump( [$action] ) ; + + my( $Date, $Heure, $Nom, $Type, $Etat, $Devise, $Hors_taxe, $Commission, $Net, + $De_l_adresse_email, $A_l_adresse_email, $N_de_transaction, $Titre_de_l_objet, + $TVA, $Nom_Option_1, $Valeur_Option_1, $N_de_transaction_de_reference, + $Adresse_1, $Adresse_2_district_quartier, $Ville, + $Etat_Province, $Code_postal, $Pays, $line_number, $line_csv, $file_csv, + $Nom_Option_2, $Option_2_Valeur ) + = @action{ ( 'Date', 'Heure', 'Nom', 'Type', 'Etat', 'Devise', 'Hors taxe', 'Commission', 'Net', + "De l'adresse email", "A l'adresse email", 'N° de transaction', "Titre de l'objet", + 'TVA', 'Nom Option 1', 'Valeur Option 1', 'Nº de transaction de référence', + 'Adresse 1', 'Adresse 2/district/quartier', 'Ville', + 'Etat/Province/Région/Comté/Territoire/Préfecture/République', 'Code postal', 'Pays', 'line_number', 'line_csv', 'file_csv', + 'Nom Option 2', 'Option 2 Valeur' ) } ; + + $Etat_Province = @action{ ( 'Etat/Province/Région/Comté/Territoire/Préfecture/République' ) } + || @action{ ( 'État/Province/Région/Comté/Territoire/Préfecture/République' ) } + || '' ; + ( $Hors_taxe ) = @action{ ( 'Hors taxe' ) } || @action{ ( 'Avant commission' ) } ; + #print "$Hors_taxe $Devise\n" ; + my $Hors_taxe_num = $Hors_taxe ; + $Hors_taxe_num =~ s{,}{.} ; + if ($Hors_taxe_num > 100) { + print "invoice $invoice $Hors_taxe_num > 100\n" ; + #return() ; + } + + my ( $email_message_header, $email_message_body ) + = build_email_message( $Date, $Nom, $De_l_adresse_email, $invoice, $Titre_de_l_objet ) ; + if ( $write_invoices and ! invoice_sent( $dir_invoices, $invoice, $De_l_adresse_email ) ) { + write_email_message( $dir_invoices, $invoice, + $email_message_header, $email_message_body, + $De_l_adresse_email) ; + write_csv_info( $dir_invoices, $invoice, $file_csv, $line_number, $line_csv ) ; + } + + + + #print "==== $invoice $refund=================================================" ; + #print $email_message ; + + my( + $clientAdrA, + $clientAdrB, + $clientAdrC, + $clientAdrD, + $clientAdrE, + $clientAdrF, + ) + = build_address( + $Nom, + $Adresse_1, + $Adresse_2_district_quartier, + $Ville, + $Code_postal, + $Etat_Province, + $Pays, + ) ; + + foreach my $str ( + $De_l_adresse_email, + $Nom, + $clientAdrA, + $clientAdrB, + $clientAdrC, + $clientAdrD, + $clientAdrE, + $clientAdrF, + ) { + $str =~ s{#}{\\#}g ; + $str =~ s{_}{\\_}g ; + $str =~ s{&}{\\&}g ; + } + + my ( $clientTypeEN, $clientTypeFR ) = client_type( $Nom_Option_1, $Valeur_Option_1 ) ; + + my $quantity = '1' ; + + my ( + $descriptionFR, + $descriptionEN, + $usageFR, + $usageEN, + ) + = description_stuff( $Titre_de_l_objet, $clientTypeEN ) ; + + my ( + $priceHT, + $tvaFR, + $tvaEN, + $priceTVA, + $priceTTC, + $messageTVAFR, + $messageTVAEN, + $priceTTCusd, + $HTorTTC + ) + = tva_stuff( $clientTypeEN, $Pays, $Hors_taxe, $Devise, $Titre_de_l_objet ) ; + + my $object_type = object_type( $Titre_de_l_objet ) ; + + my ( $urlSrc, $urlExe ) = download_urls( $Date, $object_type ) ; + #print "ZZZ $object_type ( $urlSrc, $urlExe )\n" ; + + my ( $Nom1 ) = cut( $Nom, 42 ) ; + + my $clientVAT = '' ; + + if ( ( 'VAT if professional in Europe' eq $Nom_Option_2 ) and $Option_2_Valeur ) { + $clientVAT = $Option_2_Valeur ; + } + + my $tex_variables = qq{ +%% Begin input from paypal_bilan $VERSION +\\providecommand{\\invoiceNumber}{$invoice} +\\providecommand{\\clientName}{$Nom1} +\\providecommand{\\clientEmail}{$De_l_adresse_email} +\\providecommand{\\clientAdrA}{$clientAdrA} +\\providecommand{\\clientAdrB}{$clientAdrB} +\\providecommand{\\clientAdrC}{$clientAdrC} +\\providecommand{\\clientAdrD}{$clientAdrD} +\\providecommand{\\clientAdrE}{$clientAdrE} +\\providecommand{\\clientAdrF}{$clientAdrF} +\\providecommand{\\clientVAT}{$clientVAT} +\\providecommand{\\invoiceDate}{$Date} +\\providecommand{\\invoiceHour}{$Heure} + +\\providecommand{\\descriptionFR}{$descriptionFR} +\\providecommand{\\descriptionEN}{$descriptionEN} +\\providecommand{\\usageFR}{$usageFR} +\\providecommand{\\usageEN}{$usageEN} +\\providecommand{\\quantity}{$quantity} + +\\providecommand{\\priceHT}{$priceHT} +\\providecommand{\\tvaFR}{$tvaFR} +\\providecommand{\\tvaEN}{$tvaEN} +\\providecommand{\\priceTVA}{$priceTVA} +\\providecommand{\\HTorTTC}{$HTorTTC} +\\providecommand{\\priceTTC}{$priceTTC} +\\providecommand{\\priceTTCusd}{$priceTTCusd} +\\providecommand{\\messageTVAFR}{$messageTVAFR} +\\providecommand{\\messageTVAEN}{$messageTVAEN} +\\providecommand{\\urlSrc}{\\url{$urlSrc}} +\\providecommand{\\urlExe}{\\url{$urlExe}} +%% End input from paypal_bilan +} ; + + my $tex_variables_utf8 = to_utf8( { -string => $tex_variables, -charset => 'ISO-8859-1' } ) ; + + print $tex_variables_utf8 if $debug_invoice_utf8 ; + print $tex_variables if $debug_invoice ; + + #print "$invoice ", invoice_sent( $dir_invoices, $invoice, $De_l_adresse_email ), "\n" ; + if ( $write_invoices and ! invoice_sent( $dir_invoices, $invoice, $De_l_adresse_email ) ) { + write_tex_variables_file( $dir_invoices, $invoice, $Date, $tex_variables_utf8 ) ; + } + +} + +sub description_stuff { + my ( $object, $clientTypeEN ) = @_ ; + + my $object_type = object_type( $object ) ; + + my ( $descriptionFR, $descriptionEN ) ; + if ( 'software' eq $object_type ) { + $descriptionFR = 'Logiciel imapsync. Tous droits cédés.' ; + $descriptionEN = '(Imapsync software. All rights conceded.)' ; + } + + my ( $usageFR, $usageEN ) ; + if ( 'professional' eq $clientTypeEN + and 'software' eq $object_type ) { + $usageFR = 'Usage à titre professionnel.' ; + $usageEN = '(professional usage.)' ; + } + + if ( 'individual' eq $clientTypeEN + and 'software' eq $object_type ) { + $usageFR = 'Usage à titre individuel.' ; + $usageEN = '(individual usage.)' ; + } + + if ( 'support' eq $object_type ) { + $descriptionFR = 'Support sur le logiciel imapsync.' ; + $descriptionEN = '(Imapsync support.)' ; + $usageFR = '' ; + $usageEN = '' ; + } + return( $descriptionFR, $descriptionEN, $usageFR, $usageEN ) ; +} + + + +sub object_type { + my $object = shift ; + + if ( 'imapsync' eq $object + or 'imapsync.exe' eq $object + or 'imapsync source' eq $object + or 'imapsync source code' eq $object + ) { + return( 'software' ) ; + }elsif ( 'imapsync support' eq $object ) { + return( 'support' ) ; + } +} + +sub build_email_message { + + my ( $date, $name, $email, $invoice, $objet ) = @_ ; + + my $object_type = object_type( $objet ) ; + + my $message_header_software = qq{X-imapsync: invoice $invoice for imapsync software +From: Gilles LAMIRAL +Bcc: gilles\@lamiral.info +Subject: [imapsync invoice] $invoice ($date) for imapsync software +Disposition-Notification-To: Gilles LAMIRAL +} ; + + my $message_header_support = qq{X-imapsync: invoice $invoice for imapsync support +From: Gilles LAMIRAL +Bcc: gilles\@lamiral.info +Subject: [imapsync invoice] $invoice ($date) for imapsync support +Disposition-Notification-To: Gilles LAMIRAL +} ; + + my $message_body_software = qq{ +Hello $name, + +First of all, I'm sorry for the delay in getting back to you. + +You'll find in the attachment the invoice of imapsync +software you bought and paid (dd/mm/yyyy $date). +The invoice file is named facture_imapsync-${invoice}.pdf +This invoice is in PDF format, ready to be print. + +Should you need a hardcopy of this invoice, +I'll send it to you upon request by regular mail. + +As the law requires, this numeric invoice PDF file +is signed with my private gpg key. + +The resulting gpg signature is in the file named +facture_imapsync-${invoice}.pdf.asc +you will also find in the attachment. + +You can check I (Gilles LAMIRAL) really did generate +this invoice with the following command line: + + gpg --verify facture_imapsync-${invoice}.pdf.asc facture_imapsync-${invoice}.pdf + +or any other gpg graphical tool. + +Once more, thank you for buying and using imapsync. + +Any feedback is welcome. + + +-- +Best Regards, 09 51 84 42 42 +Gilles Lamiral. France, Baulon (35580) 06 20 79 76 06 +} ; + + + my $message_body_support = qq{ +Hello $name, + +First of all, I'm sorry for the delay in getting back to you. + +You'll find in the attachment the invoice of imapsync +support you bought and paid (dd/mm/yyyy $date). +The invoice file is named facture_imapsync-${invoice}.pdf +This invoice is in PDF format, ready to be print. + +Should you need a hardcopy of this invoice, +I'll send it to you upon request by regular mail. + +As the law requires, this numeric invoice PDF file +is signed with my private gpg key. + +The resulting gpg signature is in the file named +facture_imapsync-${invoice}.pdf.asc +you will also find in the attachment. + +You can check I (Gilles LAMIRAL) really did generate +this invoice with the following command line: + + gpg --verify facture_imapsync-${invoice}.pdf.asc facture_imapsync-${invoice}.pdf + +or any other gpg graphical tool. + +Once more, thank you for buying imapsync support. + +Any feedback is welcome. + +-- +Best Regards, 09 51 84 42 42 +Gilles Lamiral. France, Baulon (35580) 06 20 79 76 06 +} ; + + + + + my $message_body_blabla = qq{ +Here is the fingerprint of my public key +pub 1024D/FDA2B3DC 2002-05-08 + Key fingerprint = 7906 F53D 0D62 0C67 304A 4CF0 6928 869B FDA2 B3DC +uid Gilles LAMIRAL +sub 1024g/A2C4CB42 2002-05-08 + +Of course the verification doesn't prove anything until +all the following conditions are met: +- you met me, +- I agree that the fingerprint above is really mine +- I prove I'm Gilles LAMIRAL with an official paper. + +Normally we won't have to verify anything unless +I disagree with this invoice and the payment +you made for imapsync. +} ; + + my ( $message_header, $message_body ) ; + if ( 'support' eq $object_type ) { + $message_header = $message_header_support ; + $message_body = $message_body_support ; + }elsif ( 'software' eq $object_type ) { + $message_header = $message_header_software ; + $message_body = $message_body_software ; + } + return( $message_header, $message_body ) ; + +} + +sub write_csv_info { + + my( $dir_invoices, $invoice, $file_csv, $line_number, $line_csv ) = @_ ; + + open( CSVINFO, "> $dir_invoices/$invoice/csv_info.txt") or die ; + print CSVINFO join( "\n", $file_csv, $line_number, $line_csv ) ; + close( CSVINFO ) ; + +} + +sub invoice_sent { + + my ( $dir_invoices, $invoice, $email_address ) = @_ ; + + return( 1 ) if ( -f "$dir_invoices/$invoice/SENT_TO_$email_address" ) ; + return( 0 ) ; + +} + +sub write_email_message { + my ( $dir_invoices, $invoice, $message_header, $message_body, $email_address ) = @_ ; + + my $message_body_utf8 = to_utf8({ -string => $message_body, -charset => 'ISO-8859-1' }); + + mkdir( "$dir_invoices/$invoice" ) or die if ! -d "$dir_invoices/$invoice" ; + + open( HEADER, "> $dir_invoices/$invoice/facture_message_header.txt") or die ; + print HEADER $message_header ; + close( HEADER ) ; + + open( BODY, "> $dir_invoices/$invoice/facture_message_body.txt") or die ; + print BODY $message_body_utf8 ; + close( BODY ) ; + + open( ADDRESS, "> $dir_invoices/$invoice/email_address.txt") or die ; + print ADDRESS "$email_address\n" ; + close( ADDRESS ) ; +} + + +sub write_tex_variables_file { + my ( $dir_invoices, $invoice, $date_jjSmmSaaaa, $tex_variables_utf8 ) = @_ ; + + mkdir( "$dir_invoices/$invoice" ) or die if ! -d "$dir_invoices/$invoice" ; + open( FILE, "> $dir_invoices/$invoice/imapsync_var.tex") or die ; + print FILE $tex_variables_utf8 ; + close( FILE ) ; + + if ( ! -f "$dir_invoices/$invoice/imapsync_var_manual.tex" ) { + open( FILE, "> $dir_invoices/$invoice/imapsync_var_manual.tex") or die ; + print FILE "%% $0 created file +%% Can be used to override imapsync_var.tex definitions\n" ; + print FILE $tex_variables_utf8 ; + close( FILE ) ; + } + +} + +sub download_urls { + my $date_jjSmmSaaaa = shift ; + my $object_type = shift ; + + my $date_aaaa_mm_jj = date_aaaa_mm_jj( $date_jjSmmSaaaa ) ; + #print "$date_aaaa_mm_jj $date_jjSmmSaaaa $object_type\n" ; + my ( $urlSrc, $urlExe ) ; + + if ('2011_05_01' le $date_aaaa_mm_jj + and 'software' eq $object_type ) { + $urlSrc = 'http://ks.lamiral.info/imapsync/paypal_return.shtml' ; + $urlExe = '' ; + return( $urlSrc, $urlExe ) ; + } + + if ('2011_05_01' le $date_aaaa_mm_jj + and 'support' eq $object_type ) { + $urlSrc = 'http://ks.lamiral.info/imapsync/paypal_return_support.shtml' ; + $urlExe = '' ; + return( $urlSrc, $urlExe ) ; + } + + if ('2011_03_24' le $date_aaaa_mm_jj) { + $urlSrc = 'http://www.linux-france.org/prj/imapsync/paypal_return.shtml' ; + $urlExe = '' ; + return( $urlSrc, $urlExe ) ; + } + if ('2011_02_21' le $date_aaaa_mm_jj) { + $urlSrc = 'http://www.linux-france.org/depot/2011_02_21/OUMbo7/' ; + $urlExe = 'http://www.linux-france.org/depot/2011_02_21/rHSVNs/' ; + return( $urlSrc, $urlExe ) ; + } + if ('2011_01_18' le $date_aaaa_mm_jj) { + $urlSrc = 'http://www.linux-france.org/depot/2011_01_18/zPRRNt/' ; + $urlExe = 'http://www.linux-france.org/depot/2011_01_18/FO1QzG/' ; + return( $urlSrc, $urlExe ) ; + } + if ('2011_01_18' le $date_aaaa_mm_jj) { + $urlSrc = 'http://www.linux-france.org/depot/2010_11_28/SiNdlZ/' ; + $urlExe = 'http://www.linux-france.org/depot/2010_11_28/R3ZAyr/' ; + return( $urlSrc, $urlExe ) ; + } + $urlSrc = 'http://www.linux-france.org/depot/2010_11_08/X2PWMe/' ; + $urlExe = 'http://www.linux-france.org/depot/2010_11_08/ZZ7zSc/' ; + return( $urlSrc, $urlExe ) ; +} + +sub date_aaaa_mm_jj { + my $date_jjSmmSaaaa = shift ; + + if ( $date_jjSmmSaaaa =~ m{(\d\d)/(\d\d)/(\d\d\d\d)} ) { + my( $jj, $mm, $aaaa ) = ( $1, $2, $3 ) ; + return( join( '_', $aaaa, $mm, $jj ) ) ; + }else{ + return( '9999_12_31' ) ; + } +} + + +sub tva_line { + my( $Devise, $Montant2, $Pays, $Nom_Option_1, $Valeur_Option_1, $Titre_de_l_objet ) = @_ ; + my( $montant_HT_EUR_exo, $montant_HT_EUR_ass, $montant_TVA_EUR ) = ( 0, 0, 0 ) ; + + my( $montant_HT_EUR_sup, $montant_TVA_EUR_sup ) = ( 0, 0 ) ; + + $Montant2 = $Montant2/$usdeur if 'USD' eq $Devise ; + + if ( 'imapsync' eq $Titre_de_l_objet + or 'imapsync.exe' eq $Titre_de_l_objet + or 'imapsync source' eq $Titre_de_l_objet + or 'imapsync source code' eq $Titre_de_l_objet + + ) { + if ( + ( 'imapsync usage' eq $Nom_Option_1 and 'individual' eq $Valeur_Option_1 ) + or + ( 'France' eq $Pays ) + ) { + $montant_HT_EUR_ass = $Montant2 / 1.196 ; + $montant_TVA_EUR = $Montant2 / 1.196 * 0.196 ; + $debug_dev and print "$Montant2 $Pays $Valeur_Option_1\n" ; + }else{ + $montant_HT_EUR_exo = $Montant2 ; + } + } + + if ( 'imapsync support' eq $Titre_de_l_objet ) { + #print "ZZZZ $Titre_de_l_objet $Montant2\n" ; + $montant_HT_EUR_sup = $Montant2 / 1.196 ; + $montant_TVA_EUR_sup = $Montant2 / 1.196 * 0.196 ; + } + + + return( $montant_HT_EUR_exo, $montant_HT_EUR_ass, $montant_TVA_EUR, $montant_HT_EUR_sup, $montant_TVA_EUR_sup ) ; +} + + + +sub tva_stuff { + my( $clientTypeEN, $Pays, $Hors_taxe, $Devise, $Titre_de_l_objet ) = @_ ; + + my $priceTTCusd = '' ; + $Hors_taxe =~ s{,}{.} ; + + if ( $Devise eq 'USD' ) { + $priceTTCusd = "(usd $Hors_taxe)" ; + $Hors_taxe = ( $Hors_taxe/$usdeur ) ; + } + + my ( + $priceHT, + $tvaFR, + $tvaEN, + $priceTVA, + $priceTTC, + $messageTVAFR, + $messageTVAEN, + $HTorTTC + ) ; + + if ( ( 'individual' eq $clientTypeEN) + or + ( 'France' eq $Pays ) + or + ( 'imapsync support' eq $Titre_de_l_objet ) + ) { + $priceHT = sprintf('%2.2f', $Hors_taxe/1.196) ; + $tvaFR = '19,60\%'; + $tvaEN = ''; + $priceTVA = sprintf('%2.2f', $Hors_taxe/1.196*0.196) ; + $priceTTC = sprintf('%2.2f', $Hors_taxe) ; + $HTorTTC = 'TTC' ; + $messageTVAFR = '' ; + $messageTVAEN = '' ; + }else{ + $priceHT = sprintf('%2.2f', $Hors_taxe) ; + $tvaFR = '' ; + $tvaEN = '' ; + $priceTVA = 'néant (none)' ; + $priceTTC = $priceHT ; + $HTorTTC = 'HT' ; + $messageTVAFR = 'Exonération de TVA, articles 262 1-2 et ter du Code Général des Impôts'; + $messageTVAEN = '(VAT tax-exempt, articles 262 1-2 and ter of French General Tax Code)'; + } + foreach my $price ( $priceHT, $priceTVA, $priceTTC, $priceTTCusd ) { + #print "[$price]\n" ; + $price =~ s{\.}{, } ; + } + return( + $priceHT, + $tvaFR, + $tvaEN, + $priceTVA, + $priceTTC, + $messageTVAFR, + $messageTVAEN, + $priceTTCusd, + $HTorTTC + ) ; +} + +sub client_type { + my ( $Nom_Option_1, $Valeur_Option_1 ) = @_ ; + + my ( $clientTypeEN, $clientTypeFR ) = ( 'professional', 'professionnel' ) ; + + if ('imapsync usage' eq $Nom_Option_1 and 'individual' eq $Valeur_Option_1 ) { + $clientTypeEN = 'individual' ; + $clientTypeFR = 'individuel' ; + }elsif ('imapsync usage' eq $Nom_Option_1 and 'professional' eq $Valeur_Option_1 ) { + $clientTypeEN = 'professional' ; + $clientTypeFR = 'professionnel' ; + } + return( $clientTypeEN, $clientTypeFR ) ; +} + +sub build_address { + my( + $Nom, + $Adresse_1, + $Adresse_2_district_quartier, + $Ville, + $Code_postal, + $Etat_Province, + $Pays, + ) = @_ ; + + my $addr = " +=========================================================== +Nom $Nom +Adresse_1 $Adresse_1 +Adresse_2_district_quartier $Adresse_2_district_quartier +Ville Code_postal $Ville $Code_postal +Etat_Province $Etat_Province +Pays $Pays +" ; + #print $addr ; + + my @address ; + $Nom = '' if ( $Nom =~ m/^\s+$/ ) ; + my( $Nom1, $Nom2 ) = cut( $Nom, 42 ) ; + push( @address, $Nom1 ) if $Nom1 ; + #push( @address, $Nom2 ) if $Nom2 ; + push( @address, $Adresse_1 ) if $Adresse_1 ; + push( @address, $Adresse_2_district_quartier ) if $Adresse_2_district_quartier ; + push( @address, "$Ville $Code_postal" ) if ( $Ville or $Code_postal ); + push( @address, $Etat_Province ) if $Etat_Province ; + push( @address, $Pays, ) if $Pays ; + + + my $clientAdrA = shift( @address ) || '' ; + my $clientAdrB = shift( @address ) || '' ; + my $clientAdrC = shift( @address ) || '' ; + my $clientAdrD = shift( @address ) || '' ; + my $clientAdrE = shift( @address ) || '' ; + my $clientAdrF = shift( @address ) || '' ; + +$addr = " +[$clientAdrA] +[$clientAdrB] +[$clientAdrC] +[$clientAdrD] +[$clientAdrE] +[$clientAdrF] +"; + #print $addr ; + + return( + $clientAdrA, + $clientAdrB, + $clientAdrC, + $clientAdrD, + $clientAdrE, + $clientAdrF, + ) ; +} + + +sub half { + my $string = shift ; + my $half = int( lenght( $string ) / 2 ) ; + # TO BE DONE + +} + +sub tests_half { + my( $aa, $bb ) = half( 'aa bb' ) ; + ok( 'aa' eq $aa, 'half: aa' ) ; + ok( 'bb' eq $bb, 'half: bb' ) ; +} + +sub cut { + my $string = shift ; + my $offset = shift ; + + return( $string, '' ) if length( $string ) < $offset ; + my $first = substr( $string, 0, $offset ) ; + my $last = substr( $string, $offset ) ; + return( $first, $last ) ; +} + +sub tests_cut { + my( $aa, $bb ) = cut("123456789", 4 ) ; + ok( '1234' eq $aa, 'cut 123456789 4 => first 1234' ) ; + ok( '56789' eq $bb, 'cut 123456789 4 => last 56789' ) ; +} diff --git a/W/paypal_reply/paypal_bilan_1.62 b/W/paypal_reply/paypal_bilan_1.62 new file mode 100755 index 0000000..d8130e8 --- /dev/null +++ b/W/paypal_reply/paypal_bilan_1.62 @@ -0,0 +1,1185 @@ +#!/usr/bin/perl + +# $Id: paypal_bilan,v 1.62 2012/12/06 18:45:02 gilles Exp gilles $ + +use strict; +use warnings; +use Getopt::Long; +use Text::CSV_XS ; +use IO::Handle ; +use Data::Dumper ; +use Unicode::MapUTF8 qw(to_utf8 from_utf8 utf8_supported_charset); +use Test::More 'no_plan' ; + +die unless (utf8_supported_charset('ISO-8859-1')); + +my $rcs = '$Id: paypal_bilan,v 1.62 2012/12/06 18:45:02 gilles Exp gilles $ ' ; +$rcs =~ m/,v (\d+\.\d+)/ ; +my $VERSION = ($1) ? $1: "UNKNOWN" ; + + +my $total_usd_received = 0 ; +my $total_usd_invoice = 0 ; +my $total_HT_EUR_exo = 0 ; +my $total_HT_EUR_ass = 0 ; +my $total_TVA_EUR = 0 ; + +my $total_HT_EUR_sup = 0 ; +my $total_TVA_EUR_sup = 0 ; + +my $total_eur_received = 0 ; +my $total_eur_invoice = 0 ; +my $nb_invoice = 0 ; +my $nb_invoice_refund = 0 ; +my $nb_invoice_suspended = 0 ; +my $nb_invoice_canceled = 0 ; + +my ( $tests, $testeur ) ; +my $debug ; +my $debug_csv ; +my $debug_dev ; +my $debug_invoice ; +my $debug_invoice_utf8 ; + +my $first_invoice = 1 ; +my $print_details = '' ; +my $bnc = '' ; +my $exportbnc = '' ; + +my $usdeur = 1.2981 ; +my $invoices ; +my %invoice_refund ; +my %invoice_canceled ; +my %invoice_suspended ; +my $write_invoices = 0 ; +my $avoid_numbers ; + +my $dir_invoices = '/g/var/paypal_invoices' ; + +my $option_ret = GetOptions ( + 'tests' => \$tests, + 'debug' => \$debug, + 'debug_csv' => \$debug_csv, + 'debug_dev' => \$debug_dev, + 'debug_invoice' => \$debug_invoice, + 'debug_invoice_utf8' => \$debug_invoice_utf8, + + 'first_invoice=i' => \$first_invoice, + 'print_details|details' => \$print_details, + 'bnc' => \$bnc, + 'exportbnc=s' => \$exportbnc, + 'usdeur=f' => \$usdeur, + 'invoices=s' => \$invoices, + 'write_invoices!' => \$write_invoices, + 'avoid_numbers=s' => \$avoid_numbers, +); + +$testeur = Test::More->builder ; +$testeur->no_ending(1) ; + +if ( $tests ) { + $testeur->no_ending( 0 ) ; + exit( tests( ) ) ; +} + + +my @files = @ARGV ; +my %action_of_invoice ; + +my %invoice_paypal ; +#$invoice_paypal{ $first_invoice } = 1 ; + +my @invoices_wanted = split( /\s+/, $invoices ) if $invoices ; + +my @avoid_numbers = split( /\s+/, $avoid_numbers ) if $avoid_numbers ; +my %avoid_numbers ; +@avoid_numbers{ @avoid_numbers } = ( ) if @avoid_numbers ; + +#print "@invoices\n" ; + +foreach my $file ( @files ) { + + my @actions = parse_file( $file ) ; + + foreach my $action (@actions) { + my %action = %$action ; + #print $action->{ Nom }, "\n" ; + my( $Date, $Heure, $Fuseau_horaire, $Nom, $Type, $Etat, + $Devise, $Montant, $Numero_davis_de_reception, $Solde, + $Pays, $Nom_Option_1, $Valeur_Option_1, $Hors_taxe, $Titre_de_l_objet, $Nom_Option_2, $Option_2_Valeur ) + = @action{ ( 'Date', 'Heure', 'Fuseau horaire', 'Nom', 'Type', 'Etat', + 'Devise', 'Montant', "Numéro d'avis de réception", 'Solde', + 'Pays', 'Nom Option 1', 'Valeur Option 1', 'Hors taxe', "Titre de l'objet", 'Nom Option 2', 'Option 2 Valeur') } ; + #print "$Nom\n" ; + ( $Etat ) = @action{ ( 'Etat' ) } || @action{ ( 'État' ) } ; + ( $Hors_taxe ) = @action{ ( 'Hors taxe' ) } || @action{ ( 'Avant commission' ) } ; + my $invoice = 'NONE' ; + $Montant = $action->{ Net } if not defined $Montant; + compute_line($action, $invoice, $Date, $Heure, $Fuseau_horaire, $Nom, $Type, $Etat, + $Devise, $Montant, $Numero_davis_de_reception, $Solde, + $Pays, $Nom_Option_1, $Valeur_Option_1, $Hors_taxe, $Titre_de_l_objet ) ; + + # index by invoice number + $action_of_invoice{ $action->{ 'invoice' } } = $action ; + } + delete $action_of_invoice{ 'NONE' } ; +} + +my $last_invoice ; +my @invoice_paypal = sort { $a <=> $b } keys %invoice_paypal ; +$last_invoice = $invoice_paypal[-1] || 0 ; +my $first_invoice_paypal = $invoice_paypal[0] || 0 ; + +@invoices_wanted = ( $first_invoice .. $last_invoice ) if ( ! @invoices_wanted ) ; + +my @invoice_sent ; +my %invoice_sent ; +my @invoice_not_sent ; +my %invoice_not_sent ; + +foreach my $invoice ( @invoices_wanted ) { + + my $action = $action_of_invoice{ $invoice } ; + next if ! $action ; + my $email_address = $action->{ "De l'adresse email" } ; + + my $invoice_sent = invoice_sent( $dir_invoices, $invoice, $email_address ) ; + #print "$invoice $invoice_sent\n" ; + + if ( $invoice_sent ) { + $invoice_sent{ $invoice }++ ; + #build_invoice( $invoice ) ; + }elsif( not ( $invoice_canceled{ $invoice } or $invoice_refund{ $invoice } ) ) { + $invoice_not_sent{ $invoice }++ ; + build_invoice( $invoice ) ; + } +} + +@invoice_sent = sort { $a <=> $b } keys( %invoice_sent ) ; +my $nb_invoice_sent = scalar( @invoice_sent ) ; +@invoice_not_sent = sort { $a <=> $b } keys( %invoice_not_sent ) ; + +my @invoice_canceled = sort { $a <=> $b } keys( %invoice_canceled ) ; +my @invoice_suspended = sort { $a <=> $b } keys( %invoice_suspended ) ; +my @invoice_refund = sort { $a <=> $b } keys( %invoice_refund ) ; + + +print( "\n", "=" x 60, "\n" ) if $bnc ; + + + +print "USD banque $total_usd_received\n" ; +print "USD invoice $total_usd_invoice\n" ; +my $total_eur_from_usd ; +$total_eur_from_usd = sprintf('%2.2f', $total_usd_invoice / $usdeur ) ; # au 30 nov 2010 http://fr.finance.yahoo.com/devises/convertisseur/#from=EUR;to=USD;amt=1 +print "EUR from USD $total_eur_from_usd\n" ; +print "EUR banque $total_eur_received\n" ; +print "EUR invoice $total_eur_invoice\n" ; + +my $total_eur = $total_eur_from_usd + $total_eur_invoice ; + +$total_HT_EUR_exo = sprintf('%2.2f', $total_HT_EUR_exo) ; +$total_HT_EUR_ass = sprintf('%2.2f', $total_HT_EUR_ass) ; +$total_TVA_EUR = sprintf('%2.2f', $total_TVA_EUR) ; + +$total_HT_EUR_sup = sprintf('%2.2f', $total_HT_EUR_sup) ; +$total_TVA_EUR_sup = sprintf('%2.2f', $total_TVA_EUR_sup) ; + +$total_eur = sprintf('%2.2f', $total_eur) ; + +print "EUR total $total_eur\n" ; +print "EUR total HT exo $total_HT_EUR_exo\n" ; +print "EUR total HT assuj $total_HT_EUR_ass\n" ; +print "EUR total TVA $total_TVA_EUR\n" ; +print "EUR total HT sup $total_HT_EUR_sup\n" ; +print "EUR total TVA sup $total_TVA_EUR_sup\n" ; +print "Nb invoice $nb_invoice ( from $first_invoice_paypal to $last_invoice )\n" ; +print "Nb invoice canceled ($nb_invoice_canceled) @invoice_canceled\n" ; +print "Nb invoice suspended ($nb_invoice_suspended) @invoice_suspended\n" ; +print "Nb invoice refund ($nb_invoice_refund) @invoice_refund\n" ; +print "Nb invoice sent $nb_invoice_sent\n" ; +print "Have to send invoices @invoice_not_sent\n" if ( @invoice_not_sent ) ; + +my $total_eur2 = $total_HT_EUR_exo + $total_HT_EUR_ass + $total_TVA_EUR + $total_HT_EUR_sup + $total_TVA_EUR_sup ; +$total_eur2 = sprintf('%2.2f', $total_eur2) ; +print "$total_eur != $total_eur2 = $total_HT_EUR_exo + $total_HT_EUR_ass + $total_TVA_EUR + $total_HT_EUR_sup + $total_TVA_EUR_sup\n" +if ( $total_eur != $total_eur2 ) ; + +sub parse_one_line_io { + my $csv = shift ; + my $io = shift ; + + my $line = $csv->getline($io) ; + + return if ( $csv->eof( ) ) ; + if ( not defined( $line ) ) { + my($cde, $str, $pos) = $csv->error_diag () ; + print "[$cde] [$str] [$pos]\n" ; + + } + return( $line ) ; +} + +sub hash_and_count_dupplicate { + my @columns = @_ ; + my %columns ; + + #@columns_def{ @columns_def } = ( ) ; + foreach my $col ( @columns ) { + $columns{ $col } += 1 ; + } + $debug_csv and print "Nb columns: ", scalar( keys %columns ), " ", scalar( @columns ), "\n" ; + # debug how many time a title is defined + foreach my $col (1 .. scalar( @columns )) { + $debug_csv and print "$col | ", + deci_to_AA( $col ) , " | ", + $columns{ $columns[ $col - 1 ] }, " | ", + $columns[ $col - 1 ], "\n" ; + } + + # exit in case two columns have the same name + die "Erreur : doublons dans les titres\n" if ( scalar( keys %columns ) != scalar( @columns ) ) ; + + return( %columns ) ; +} + +sub deci_to_AA { + my $deci = shift ; + my $AA = ''; + + while ( $deci > 0 ) { + my $quot = int( ( $deci - 1 ) / 26 ) ; + my $rest = $deci - 1 - ( 26 * $quot ) ; + my $char = chr ( ord('A') + $rest ) ; + $AA = $char . $AA ; + $deci = $quot ; + } + #print "col=$AA\n" ; + return( $AA ) ; +} + +sub remove_first_blank { + my $string = shift ; + + $string =~ s/^ +// ; + return( $string ) ; + +} + +sub parse_file { + my $file = shift ; + + open my $io, "<", $file or die "$file: $!" ; + + my $csv = Text::CSV_XS->new( { + sep_char => ',', + binary => 1, + keep_meta_info => 1, + eol => $/, + } ) ; + + my $line_1 = parse_one_line_io( $csv, $io ) ; + die if ( not defined $line_1 ) ; # first line must have no problem + + my @columns_def_orig = @$line_1 ; + my @columns_def = map { remove_first_blank( $_ ) } @columns_def_orig ; + $debug_csv and print "columns_def = ", map( { "[$_]" } @columns_def ), "\n"; + + my %columns_def = hash_and_count_dupplicate( @columns_def ) ; + my $nb_columns_def = scalar @columns_def ; + + my $line_counter = 2 ; + my @actions ; + while ( 1 ) { + $debug_csv and print "ligne $line_counter ", $csv->eof( ), "\n" ; + my $line = parse_one_line_io( $csv, $io ) ; + last if ( $csv->eof( ) ) ; + if ( not defined $line ) { + print "Erreur ligne $line_counter : ", $csv->error_diag, "\n\n"; + ++$line_counter ; + next ; + } + my @columns = @$line ; + + if ( $nb_columns_def != scalar @columns ) { + print "Erreur ligne $line_counter : nombre de colonnes = ", scalar @columns, " != $nb_columns_def\n" ; + ++$line_counter ; + next ; + } + my %columns ; + @columns{ @columns_def } = @columns ; + $columns{ 'file_csv' } = $file ; + $columns{ 'line_number' } = $line_counter ; + $csv->combine( @columns ) ; + my $line_csv = $csv->string(); + $columns{ 'line_csv' } = $line_csv ; + $debug_csv and print map( { "[$_] = [" . $columns{$_} . "]\n" } + @columns_def, 'line_number', 'line_csv', 'file_csv' ), + "\n"; + ++$line_counter ; + push( @actions, \%columns ) ; + } + close( $io ); + return( reverse @actions ) ; +} + +sub next_invoice { + my @current_numbers = sort { $a <=> $b } ( $first_invoice - 1, keys( %invoice_paypal ) ) ; + my $last_invoice = $current_numbers[ -1 ] || 0 ; + + #keys( %avoid_numbers ), + my $next_invoice = $last_invoice + 1 ; + while ( exists( $avoid_numbers{ $next_invoice } ) ) { $next_invoice++ ; } + $invoice_paypal{ $next_invoice } = 1 ; + #print "AAA [@current_numbers] [$last_invoice] [$next_invoice]\n" ; + + return( $next_invoice ) ; +} + +sub keyval { + my %hash = @_ ; + return( join( " ", map( { "$_ => " . $hash{ $_ } } keys %hash ) ) . "\n" ) ; +} + + +sub invoice_00000 { + my $invoice = shift ; + + return( sprintf( "%05d", $invoice ) ) ; +} + +sub tests_invoice_00000 { + + ok( '00000' eq invoice_00000( 0 ), 'invoice_00000: 0 -> 00000' ) ; + ok( '00147' eq invoice_00000( 147 ), 'invoice_00000: 147 -> 00147' ) ; + ok( '99999' eq invoice_00000( 99999 ), 'invoice_00000: 9999 -> 99999' ) ; +} + +sub tests_next_invoice { + ok( 1 == next_invoice( ), 'next_invoice: 1' ) ; + ok( 2 == next_invoice( ), 'next_invoice: 2' ) ; + @avoid_numbers{ (3, 4, 6, 8 ) } = ( ) ; + ok( 5 == next_invoice( ), 'next_invoice: 7' ) ; + ok( 7 == next_invoice( ), 'next_invoice: 8' ) ; + ok( 9 == next_invoice( ), 'next_invoice: 9' ) ; + %invoice_paypal = () ; + $first_invoice = 7 ; + ok( 7 == next_invoice( ), 'next_invoice: 7' ) ; +} + + +sub tests { + tests_next_invoice( ) ; + #tests_half( ) ; + tests_cut( ) ; + tests_invoice_00000( ) ; +} + +sub compute_line { + my( $action, $invoice, $Date, $Heure, $Fuseau_horaire, $Nom, $Type, $Etat, + $Devise, $Montant, $Numero_davis_de_reception, $Solde, + $Pays, $Nom_Option_1, $Valeur_Option_1, $Hors_taxe_paypal, $Titre_de_l_objet ) = @_ ; + + $debug and print( "-" x 60, "\n", + "[$Date] [$Heure] [$Fuseau_horaire] [$Nom] [$Type] [$Etat] ", + "[$Devise] [$Hors_taxe_paypal] [$Montant] [$Numero_davis_de_reception] [$Solde]\n", + "[$Pays] [$Nom_Option_1] [$Valeur_Option_1] [$Titre_de_l_objet]\n" ) ; + + $Montant =~ s/[^0-9-,.]//g ; + $Montant =~ s/,/./g ; + #$debug and print "MM[$Montant]\n" ; + $Hors_taxe_paypal =~ s/,/./g ; + + my $MontantEUR; + my( $montant_HT_EUR_exo, $montant_HT_EUR_ass, $montant_TVA_EUR ) ; + my( $montant_HT_EUR_sup, $montant_TVA_EUR_sup ) ; + + if ( $bnc ) { + $MontantEUR = $Montant ; + $MontantEUR = sprintf( "%.4f", $Montant/$usdeur ) if ($Devise eq 'USD') ; + print( "\n", "=" x 60, "\n" ) ; + print( "[$Date] [$Nom] [$Type] [$Etat] [$Devise] [$Hors_taxe_paypal] [$Montant] [EUR $MontantEUR]\n", + "[$Pays] [$Nom_Option_1] [$Valeur_Option_1] [$Titre_de_l_objet]\n" ) ; + } + + if ( + 'Paiement sur site marchand reçu' eq $Type + and 'USD' eq $Devise + and ( 'Terminé' eq $Etat or 'Compensé' eq $Etat ) + ) { + $Montant =~tr/,/./; + #print "$Montant\n" ; + my $Montant2_usd; + $Montant2_usd = $Hors_taxe_paypal ; + $total_usd_received += $Montant ; + $total_usd_invoice += $Montant2_usd ; + ( $montant_HT_EUR_exo, $montant_HT_EUR_ass, $montant_TVA_EUR, $montant_HT_EUR_sup, $montant_TVA_EUR_sup ) + = tva_line( $Devise, $Montant2_usd, $Pays, $Nom_Option_1, $Valeur_Option_1, $Titre_de_l_objet ) ; + $total_HT_EUR_exo += $montant_HT_EUR_exo ; + $total_HT_EUR_ass += $montant_HT_EUR_ass ; + $total_TVA_EUR += $montant_TVA_EUR ; + #$invoice = $first_invoice + $nb_invoice ; + $invoice = next_invoice( ) ; + $nb_invoice++ ; + $print_details and print ( "[$invoice] [$Date] [$Heure] [$Fuseau_horaire] [$Nom] [$Type] [$Etat] [$Devise] [$Montant] [$Numero_davis_de_reception] [$Solde]\n" ) ; + + } + + if ( + 'Paiement sur site marchand reçu' eq $Type + and 'EUR' eq $Devise + and ( 'Terminé' eq $Etat or 'Compensé' eq $Etat ) + ) { + $Montant =~tr/,/./; + #print "$Montant\n" ; + my $Montant2_eur; + $Montant2_eur = $Hors_taxe_paypal ; + $total_eur_received += $Montant ; + $total_eur_invoice += $Montant2_eur ; + ( $montant_HT_EUR_exo, $montant_HT_EUR_ass, $montant_TVA_EUR, $montant_HT_EUR_sup, $montant_TVA_EUR_sup ) + = tva_line( $Devise, $Montant2_eur, $Pays, $Nom_Option_1, $Valeur_Option_1, $Titre_de_l_objet ) ; + $total_HT_EUR_exo += $montant_HT_EUR_exo ; + $total_HT_EUR_ass += $montant_HT_EUR_ass ; + $total_TVA_EUR += $montant_TVA_EUR ; + $total_HT_EUR_sup += $montant_HT_EUR_sup ; + $total_TVA_EUR_sup += $montant_TVA_EUR_sup ; + + + #$invoice = $first_invoice + $nb_invoice ; + $invoice = next_invoice( ) ; + $nb_invoice++ ; + $print_details and print ( "[$invoice] [$Date] [$Heure] [$Fuseau_horaire] [$Nom] [$Type] [$Etat] [$Devise] [$Montant] [$Numero_davis_de_reception] [$Solde]\n" ) ; + } + + if ( + 'Paiement sur site marchand reçu' eq $Type + and 'EUR' eq $Devise + and 'Remboursé' eq $Etat + ) { + $invoice = next_invoice( ) ; + $nb_invoice++ ; + $nb_invoice_refund++; + $invoice_refund{ $invoice }++ ; + + $print_details and print ( "[$invoice] [$Date] [$Heure] [$Fuseau_horaire] [$Nom] [$Type] [$Etat] [$Devise] [$Montant] [$Numero_davis_de_reception] [$Solde]\n" ) ; + } + + if ( + 'Paiement sur site marchand reçu' eq $Type + and 'EUR' eq $Devise + and 'Annulé' eq $Etat + ) { + $invoice = next_invoice( ) ; + $nb_invoice++ ; + $nb_invoice_canceled++; + $invoice_canceled{ $invoice }++ ; + + $print_details and print ( "[$invoice] [$Date] [$Heure] [$Fuseau_horaire] [$Nom] [$Type] [$Etat] [$Devise] [$Montant] [$Numero_davis_de_reception] [$Solde]\n" ) ; + } + + if ( + 'Paiement sur site marchand reçu' eq $Type + and 'EUR' eq $Devise + and 'Suspendu' eq $Etat + ) { + $invoice = next_invoice( ) ; + $nb_invoice++ ; + $nb_invoice_suspended++; + $invoice_suspended{ $invoice }++ ; + + $print_details and print ( "[$invoice] [$Date] [$Heure] [$Fuseau_horaire] [$Nom] [$Type] [$Etat] [$Devise] [$Montant] [$Numero_davis_de_reception] [$Solde]\n" ) ; + } + + if ( + 'Paiement sur site marchand reçu' eq $Type + and 'EUR' eq $Devise + and 'Non compensé' eq $Etat + ) { + $invoice = next_invoice( ) ; + $nb_invoice++ ; + $print_details and print ( "[$invoice] [$Date] [$Heure] [$Fuseau_horaire] [$Nom] [$Type] [$Etat] [$Devise] [$Montant] [$Numero_davis_de_reception] [$Solde]\n" ) ; + } + + $action->{ 'invoice' } = $invoice ; + if ( $bnc ) { + my $FR_flag = '' ; + $FR_flag = ' FR' if $Pays eq 'France' ; + my $IND_flag = '' ; + $IND_flag = ' IND' if ('imapsync usage' eq $Nom_Option_1 and 'individual' eq $Valeur_Option_1 ) ; + my $SUPPORT_flag = '' ; + $SUPPORT_flag = ' support' if ( 'imapsync support' eq $Titre_de_l_objet ) ; + #print "FE $invoice$FR_flag$IND_flag\n" ; + #printf( "%.2f [EUR %.2f]\n", $Montant, $MontantEUR ) ; + print "FE $invoice$FR_flag$IND_flag imapsync$SUPPORT_flag $Nom\n" ; + print "[$Date]$FR_flag$IND_flag $MontantEUR $Devise \n" ; + } +} + +sub build_invoice { + my $invoice = shift ; + + return if ! $invoice ; + + my $action = $action_of_invoice{ $invoice } ; + my $refund = '' ; + $refund = 'REFUND ' if $invoice_refund{ $invoice } ; + my %action = %$action if $action ; + #print Data::Dumper->Dump( [$action] ) ; + + my( $Date, $Heure, $Nom, $Type, $Etat, $Devise, $Hors_taxe, $Commission, $Net, + $De_l_adresse_email, $A_l_adresse_email, $N_de_transaction, $Titre_de_l_objet, + $TVA, $Nom_Option_1, $Valeur_Option_1, $N_de_transaction_de_reference, + $Adresse_1, $Adresse_2_district_quartier, $Ville, + $Etat_Province, $Code_postal, $Pays, $line_number, $line_csv, $file_csv, + $Nom_Option_2, $Option_2_Valeur ) + = @action{ ( 'Date', 'Heure', 'Nom', 'Type', 'Etat', 'Devise', 'Hors taxe', 'Commission', 'Net', + "De l'adresse email", "A l'adresse email", 'N° de transaction', "Titre de l'objet", + 'TVA', 'Nom Option 1', 'Valeur Option 1', 'Nº de transaction de référence', + 'Adresse 1', 'Adresse 2/district/quartier', 'Ville', + 'Etat/Province/Région/Comté/Territoire/Préfecture/République', 'Code postal', 'Pays', 'line_number', 'line_csv', 'file_csv', + 'Nom Option 2', 'Option 2 Valeur' ) } ; + + $Etat_Province = @action{ ( 'Etat/Province/Région/Comté/Territoire/Préfecture/République' ) } + || @action{ ( 'État/Province/Région/Comté/Territoire/Préfecture/République' ) } + || '' ; + ( $Hors_taxe ) = @action{ ( 'Hors taxe' ) } || @action{ ( 'Avant commission' ) } ; + #print "$Hors_taxe $Devise\n" ; + my $Hors_taxe_num = $Hors_taxe ; + $Hors_taxe_num =~ s{,}{.} ; + if ($Hors_taxe_num > 100) { + print "invoice $invoice $Hors_taxe_num > 100\n" ; + #return() ; + } + + my ( $email_message_header, $email_message_body ) + = build_email_message( $Date, $Nom, $De_l_adresse_email, $invoice, $Titre_de_l_objet ) ; + if ( $write_invoices and ! invoice_sent( $dir_invoices, $invoice, $De_l_adresse_email ) ) { + write_email_message( $dir_invoices, $invoice, + $email_message_header, $email_message_body, + $De_l_adresse_email) ; + write_csv_info( $dir_invoices, $invoice, $file_csv, $line_number, $line_csv ) ; + } + + + + #print "==== $invoice $refund=================================================" ; + #print $email_message ; + + my( + $clientAdrA, + $clientAdrB, + $clientAdrC, + $clientAdrD, + $clientAdrE, + $clientAdrF, + ) + = build_address( + $Nom, + $Adresse_1, + $Adresse_2_district_quartier, + $Ville, + $Code_postal, + $Etat_Province, + $Pays, + ) ; + + foreach my $str ( + $De_l_adresse_email, + $Nom, + $clientAdrA, + $clientAdrB, + $clientAdrC, + $clientAdrD, + $clientAdrE, + $clientAdrF, + ) { + $str =~ s{#}{\\#}g ; + $str =~ s{_}{\\_}g ; + $str =~ s{&}{\\&}g ; + } + + my ( $clientTypeEN, $clientTypeFR ) = client_type( $Nom_Option_1, $Valeur_Option_1 ) ; + + my $quantity = '1' ; + + my ( + $descriptionFR, + $descriptionEN, + $usageFR, + $usageEN, + ) + = description_stuff( $Titre_de_l_objet, $clientTypeEN ) ; + + my ( + $priceHT, + $tvaFR, + $tvaEN, + $priceTVA, + $priceTTC, + $messageTVAFR, + $messageTVAEN, + $priceTTCusd, + $HTorTTC + ) + = tva_stuff( $clientTypeEN, $Pays, $Hors_taxe, $Devise, $Titre_de_l_objet ) ; + + my $object_type = object_type( $Titre_de_l_objet ) ; + + my ( $urlSrc, $urlExe ) = download_urls( $Date, $object_type ) ; + #print "ZZZ $object_type ( $urlSrc, $urlExe )\n" ; + + my ( $Nom1 ) = cut( $Nom, 42 ) ; + + my $clientVAT = '' ; + + if ( ( 'VAT if professional in Europe' eq $Nom_Option_2 ) and $Option_2_Valeur ) { + $clientVAT = $Option_2_Valeur ; + } + + my $tex_variables = qq{ +%% Begin input from paypal_bilan $VERSION +\\providecommand{\\invoiceNumber}{$invoice} +\\providecommand{\\clientName}{$Nom1} +\\providecommand{\\clientEmail}{$De_l_adresse_email} +\\providecommand{\\clientAdrA}{$clientAdrA} +\\providecommand{\\clientAdrB}{$clientAdrB} +\\providecommand{\\clientAdrC}{$clientAdrC} +\\providecommand{\\clientAdrD}{$clientAdrD} +\\providecommand{\\clientAdrE}{$clientAdrE} +\\providecommand{\\clientAdrF}{$clientAdrF} +\\providecommand{\\clientVAT}{$clientVAT} +\\providecommand{\\invoiceDate}{$Date} +\\providecommand{\\invoiceHour}{$Heure} + +\\providecommand{\\descriptionFR}{$descriptionFR} +\\providecommand{\\descriptionEN}{$descriptionEN} +\\providecommand{\\usageFR}{$usageFR} +\\providecommand{\\usageEN}{$usageEN} +\\providecommand{\\quantity}{$quantity} + +\\providecommand{\\priceHT}{$priceHT} +\\providecommand{\\tvaFR}{$tvaFR} +\\providecommand{\\tvaEN}{$tvaEN} +\\providecommand{\\priceTVA}{$priceTVA} +\\providecommand{\\HTorTTC}{$HTorTTC} +\\providecommand{\\priceTTC}{$priceTTC} +\\providecommand{\\priceTTCusd}{$priceTTCusd} +\\providecommand{\\messageTVAFR}{$messageTVAFR} +\\providecommand{\\messageTVAEN}{$messageTVAEN} +\\providecommand{\\urlSrc}{\\url{$urlSrc}} +\\providecommand{\\urlExe}{\\url{$urlExe}} +%% End input from paypal_bilan +} ; + + my $tex_variables_utf8 = to_utf8( { -string => $tex_variables, -charset => 'ISO-8859-1' } ) ; + + print $tex_variables_utf8 if $debug_invoice_utf8 ; + print $tex_variables if $debug_invoice ; + + #print "$invoice ", invoice_sent( $dir_invoices, $invoice, $De_l_adresse_email ), "\n" ; + if ( $write_invoices and ! invoice_sent( $dir_invoices, $invoice, $De_l_adresse_email ) ) { + write_tex_variables_file( $dir_invoices, $invoice, $Date, $tex_variables_utf8 ) ; + } + +} + +sub description_stuff { + my ( $object, $clientTypeEN ) = @_ ; + + my $object_type = object_type( $object ) ; + + my ( $descriptionFR, $descriptionEN ) ; + if ( 'software' eq $object_type ) { + $descriptionFR = 'Logiciel imapsync. Tous droits cédés.' ; + $descriptionEN = '(Imapsync software. All rights conceded.)' ; + } + + my ( $usageFR, $usageEN ) ; + if ( 'professional' eq $clientTypeEN + and 'software' eq $object_type ) { + $usageFR = 'Usage à titre professionnel.' ; + $usageEN = '(professional usage.)' ; + } + + if ( 'individual' eq $clientTypeEN + and 'software' eq $object_type ) { + $usageFR = 'Usage à titre individuel.' ; + $usageEN = '(individual usage.)' ; + } + + if ( 'support' eq $object_type ) { + $descriptionFR = 'Support sur le logiciel imapsync.' ; + $descriptionEN = '(Imapsync support.)' ; + $usageFR = '' ; + $usageEN = '' ; + } + return( $descriptionFR, $descriptionEN, $usageFR, $usageEN ) ; +} + + + +sub object_type { + my $object = shift ; + + if ( 'imapsync' eq $object + or 'imapsync.exe' eq $object + or 'imapsync source' eq $object + or 'imapsync source code' eq $object + ) { + return( 'software' ) ; + }elsif ( 'imapsync support' eq $object ) { + return( 'support' ) ; + } +} + +sub build_email_message { + + my ( $date, $name, $email, $invoice, $objet ) = @_ ; + + my $object_type = object_type( $objet ) ; + + my $message_header_software = qq{X-imapsync: invoice $invoice for imapsync software +From: Gilles LAMIRAL +Bcc: gilles\@lamiral.info +Subject: [imapsync invoice] $invoice ($date) for imapsync software +Disposition-Notification-To: Gilles LAMIRAL +} ; + + my $message_header_support = qq{X-imapsync: invoice $invoice for imapsync support +From: Gilles LAMIRAL +Bcc: gilles\@lamiral.info +Subject: [imapsync invoice] $invoice ($date) for imapsync support +Disposition-Notification-To: Gilles LAMIRAL +} ; + + my $message_body_software = qq{ +Hello $name, + +First of all, I'm sorry for the delay in getting back to you. + +You'll find in the attachment the invoice of imapsync +software you bought and paid (dd/mm/yyyy $date). +The invoice file is named facture_imapsync-${invoice}.pdf +This invoice is in PDF format, ready to be print. + +Should you need a hardcopy of this invoice, +I'll send it to you upon request by regular mail. + +As the law requires, this numeric invoice PDF file +is signed with my private gpg key. + +The resulting gpg signature is in the file named +facture_imapsync-${invoice}.pdf.asc +you will also find in the attachment. + +You can check I (Gilles LAMIRAL) really did generate +this invoice with the following command line: + + gpg --verify facture_imapsync-${invoice}.pdf.asc facture_imapsync-${invoice}.pdf + +or any other gpg graphical tool. + +Once more, thank you for buying and using imapsync. + +Any feedback is welcome. + + +-- +Best Regards, 09 51 84 42 42 +Gilles Lamiral. France, Baulon (35580) 06 20 79 76 06 +} ; + + + my $message_body_support = qq{ +Hello $name, + +First of all, I'm sorry for the delay in getting back to you. + +You'll find in the attachment the invoice of imapsync +support you bought and paid (dd/mm/yyyy $date). +The invoice file is named facture_imapsync-${invoice}.pdf +This invoice is in PDF format, ready to be print. + +Should you need a hardcopy of this invoice, +I'll send it to you upon request by regular mail. + +As the law requires, this numeric invoice PDF file +is signed with my private gpg key. + +The resulting gpg signature is in the file named +facture_imapsync-${invoice}.pdf.asc +you will also find in the attachment. + +You can check I (Gilles LAMIRAL) really did generate +this invoice with the following command line: + + gpg --verify facture_imapsync-${invoice}.pdf.asc facture_imapsync-${invoice}.pdf + +or any other gpg graphical tool. + +Once more, thank you for buying imapsync support. + +Any feedback is welcome. + +-- +Best Regards, 09 51 84 42 42 +Gilles Lamiral. France, Baulon (35580) 06 20 79 76 06 +} ; + + + + + my $message_body_blabla = qq{ +Here is the fingerprint of my public key +pub 1024D/FDA2B3DC 2002-05-08 + Key fingerprint = 7906 F53D 0D62 0C67 304A 4CF0 6928 869B FDA2 B3DC +uid Gilles LAMIRAL +sub 1024g/A2C4CB42 2002-05-08 + +Of course the verification doesn't prove anything until +all the following conditions are met: +- you met me, +- I agree that the fingerprint above is really mine +- I prove I'm Gilles LAMIRAL with an official paper. + +Normally we won't have to verify anything unless +I disagree with this invoice and the payment +you made for imapsync. +} ; + + my ( $message_header, $message_body ) ; + if ( 'support' eq $object_type ) { + $message_header = $message_header_support ; + $message_body = $message_body_support ; + }elsif ( 'software' eq $object_type ) { + $message_header = $message_header_software ; + $message_body = $message_body_software ; + } + return( $message_header, $message_body ) ; + +} + +sub write_csv_info { + + my( $dir_invoices, $invoice, $file_csv, $line_number, $line_csv ) = @_ ; + + open( CSVINFO, "> $dir_invoices/$invoice/csv_info.txt") or die ; + print CSVINFO join( "\n", $file_csv, $line_number, $line_csv ) ; + close( CSVINFO ) ; + +} + +sub invoice_sent { + + my ( $dir_invoices, $invoice, $email_address ) = @_ ; + + return( 1 ) if ( -f "$dir_invoices/$invoice/SENT_TO_$email_address" ) ; + return( 0 ) ; + +} + +sub write_email_message { + my ( $dir_invoices, $invoice, $message_header, $message_body, $email_address ) = @_ ; + + my $message_body_utf8 = to_utf8({ -string => $message_body, -charset => 'ISO-8859-1' }); + + mkdir( "$dir_invoices/$invoice" ) or die if ! -d "$dir_invoices/$invoice" ; + + open( HEADER, "> $dir_invoices/$invoice/facture_message_header.txt") or die ; + print HEADER $message_header ; + close( HEADER ) ; + + open( BODY, "> $dir_invoices/$invoice/facture_message_body.txt") or die ; + print BODY $message_body_utf8 ; + close( BODY ) ; + + open( ADDRESS, "> $dir_invoices/$invoice/email_address.txt") or die ; + print ADDRESS "$email_address\n" ; + close( ADDRESS ) ; +} + + +sub write_tex_variables_file { + my ( $dir_invoices, $invoice, $date_jjSmmSaaaa, $tex_variables_utf8 ) = @_ ; + + mkdir( "$dir_invoices/$invoice" ) or die if ! -d "$dir_invoices/$invoice" ; + open( FILE, "> $dir_invoices/$invoice/imapsync_var.tex") or die ; + print FILE $tex_variables_utf8 ; + close( FILE ) ; + + if ( ! -f "$dir_invoices/$invoice/imapsync_var_manual.tex" ) { + open( FILE, "> $dir_invoices/$invoice/imapsync_var_manual.tex") or die ; + print FILE "%% $0 created file +%% Can be used to override imapsync_var.tex definitions\n" ; + print FILE $tex_variables_utf8 ; + close( FILE ) ; + } + +} + +sub download_urls { + my $date_jjSmmSaaaa = shift ; + my $object_type = shift ; + + my $date_aaaa_mm_jj = date_aaaa_mm_jj( $date_jjSmmSaaaa ) ; + #print "$date_aaaa_mm_jj $date_jjSmmSaaaa $object_type\n" ; + my ( $urlSrc, $urlExe ) ; + + if ('2011_05_01' le $date_aaaa_mm_jj + and 'software' eq $object_type ) { + $urlSrc = 'http://ks.lamiral.info/imapsync/paypal_return.shtml' ; + $urlExe = '' ; + return( $urlSrc, $urlExe ) ; + } + + if ('2011_05_01' le $date_aaaa_mm_jj + and 'support' eq $object_type ) { + $urlSrc = 'http://ks.lamiral.info/imapsync/paypal_return_support.shtml' ; + $urlExe = '' ; + return( $urlSrc, $urlExe ) ; + } + + if ('2011_03_24' le $date_aaaa_mm_jj) { + $urlSrc = 'http://www.linux-france.org/prj/imapsync/paypal_return.shtml' ; + $urlExe = '' ; + return( $urlSrc, $urlExe ) ; + } + if ('2011_02_21' le $date_aaaa_mm_jj) { + $urlSrc = 'http://www.linux-france.org/depot/2011_02_21/OUMbo7/' ; + $urlExe = 'http://www.linux-france.org/depot/2011_02_21/rHSVNs/' ; + return( $urlSrc, $urlExe ) ; + } + if ('2011_01_18' le $date_aaaa_mm_jj) { + $urlSrc = 'http://www.linux-france.org/depot/2011_01_18/zPRRNt/' ; + $urlExe = 'http://www.linux-france.org/depot/2011_01_18/FO1QzG/' ; + return( $urlSrc, $urlExe ) ; + } + if ('2011_01_18' le $date_aaaa_mm_jj) { + $urlSrc = 'http://www.linux-france.org/depot/2010_11_28/SiNdlZ/' ; + $urlExe = 'http://www.linux-france.org/depot/2010_11_28/R3ZAyr/' ; + return( $urlSrc, $urlExe ) ; + } + $urlSrc = 'http://www.linux-france.org/depot/2010_11_08/X2PWMe/' ; + $urlExe = 'http://www.linux-france.org/depot/2010_11_08/ZZ7zSc/' ; + return( $urlSrc, $urlExe ) ; +} + +sub date_aaaa_mm_jj { + my $date_jjSmmSaaaa = shift ; + + if ( $date_jjSmmSaaaa =~ m{(\d\d)/(\d\d)/(\d\d\d\d)} ) { + my( $jj, $mm, $aaaa ) = ( $1, $2, $3 ) ; + return( join( '_', $aaaa, $mm, $jj ) ) ; + }else{ + return( '9999_12_31' ) ; + } +} + + +sub tva_line { + my( $Devise, $Montant2, $Pays, $Nom_Option_1, $Valeur_Option_1, $Titre_de_l_objet ) = @_ ; + my( $montant_HT_EUR_exo, $montant_HT_EUR_ass, $montant_TVA_EUR ) = ( 0, 0, 0 ) ; + + my( $montant_HT_EUR_sup, $montant_TVA_EUR_sup ) = ( 0, 0 ) ; + + $Montant2 = $Montant2/$usdeur if 'USD' eq $Devise ; + + if ( 'imapsync' eq $Titre_de_l_objet + or 'imapsync.exe' eq $Titre_de_l_objet + or 'imapsync source' eq $Titre_de_l_objet + or 'imapsync source code' eq $Titre_de_l_objet + + ) { + if ( + ( 'imapsync usage' eq $Nom_Option_1 and 'individual' eq $Valeur_Option_1 ) + or + ( 'France' eq $Pays ) + ) { + $montant_HT_EUR_ass = $Montant2 / 1.196 ; + $montant_TVA_EUR = $Montant2 / 1.196 * 0.196 ; + $debug_dev and print "$Montant2 $Pays $Valeur_Option_1\n" ; + }else{ + $montant_HT_EUR_exo = $Montant2 ; + } + } + + if ( 'imapsync support' eq $Titre_de_l_objet ) { + #print "ZZZZ $Titre_de_l_objet $Montant2\n" ; + $montant_HT_EUR_sup = $Montant2 / 1.196 ; + $montant_TVA_EUR_sup = $Montant2 / 1.196 * 0.196 ; + } + + + return( $montant_HT_EUR_exo, $montant_HT_EUR_ass, $montant_TVA_EUR, $montant_HT_EUR_sup, $montant_TVA_EUR_sup ) ; +} + + + +sub tva_stuff { + my( $clientTypeEN, $Pays, $Hors_taxe, $Devise, $Titre_de_l_objet ) = @_ ; + + my $priceTTCusd = '' ; + $Hors_taxe =~ s{,}{.} ; + + if ( $Devise eq 'USD' ) { + $priceTTCusd = "(usd $Hors_taxe)" ; + $Hors_taxe = ( $Hors_taxe/$usdeur ) ; + } + + my ( + $priceHT, + $tvaFR, + $tvaEN, + $priceTVA, + $priceTTC, + $messageTVAFR, + $messageTVAEN, + $HTorTTC + ) ; + + if ( ( 'individual' eq $clientTypeEN) + or + ( 'France' eq $Pays ) + or + ( 'imapsync support' eq $Titre_de_l_objet ) + ) { + $priceHT = sprintf('%2.2f', $Hors_taxe/1.196) ; + $tvaFR = '19,60\%'; + $tvaEN = ''; + $priceTVA = sprintf('%2.2f', $Hors_taxe/1.196*0.196) ; + $priceTTC = sprintf('%2.2f', $Hors_taxe) ; + $HTorTTC = 'TTC' ; + $messageTVAFR = '' ; + $messageTVAEN = '' ; + }else{ + $priceHT = sprintf('%2.2f', $Hors_taxe) ; + $tvaFR = '' ; + $tvaEN = '' ; + $priceTVA = 'néant (none)' ; + $priceTTC = $priceHT ; + $HTorTTC = 'HT' ; + $messageTVAFR = 'Exonération de TVA, articles 262 1-2 et ter du Code Général des Impôts'; + $messageTVAEN = '(VAT tax-exempt, articles 262 1-2 and ter of French General Tax Code)'; + } + foreach my $price ( $priceHT, $priceTVA, $priceTTC, $priceTTCusd ) { + #print "[$price]\n" ; + $price =~ s{\.}{, } ; + } + return( + $priceHT, + $tvaFR, + $tvaEN, + $priceTVA, + $priceTTC, + $messageTVAFR, + $messageTVAEN, + $priceTTCusd, + $HTorTTC + ) ; +} + +sub client_type { + my ( $Nom_Option_1, $Valeur_Option_1 ) = @_ ; + + my ( $clientTypeEN, $clientTypeFR ) = ( 'professional', 'professionnel' ) ; + + if ('imapsync usage' eq $Nom_Option_1 and 'individual' eq $Valeur_Option_1 ) { + $clientTypeEN = 'individual' ; + $clientTypeFR = 'individuel' ; + }elsif ('imapsync usage' eq $Nom_Option_1 and 'professional' eq $Valeur_Option_1 ) { + $clientTypeEN = 'professional' ; + $clientTypeFR = 'professionnel' ; + } + return( $clientTypeEN, $clientTypeFR ) ; +} + +sub build_address { + my( + $Nom, + $Adresse_1, + $Adresse_2_district_quartier, + $Ville, + $Code_postal, + $Etat_Province, + $Pays, + ) = @_ ; + + my $addr = " +=========================================================== +Nom $Nom +Adresse_1 $Adresse_1 +Adresse_2_district_quartier $Adresse_2_district_quartier +Ville Code_postal $Ville $Code_postal +Etat_Province $Etat_Province +Pays $Pays +" ; + #print $addr ; + + my @address ; + $Nom = '' if ( $Nom =~ m/^\s+$/ ) ; + my( $Nom1, $Nom2 ) = cut( $Nom, 42 ) ; + push( @address, $Nom1 ) if $Nom1 ; + #push( @address, $Nom2 ) if $Nom2 ; + push( @address, $Adresse_1 ) if $Adresse_1 ; + push( @address, $Adresse_2_district_quartier ) if $Adresse_2_district_quartier ; + push( @address, "$Ville $Code_postal" ) if ( $Ville or $Code_postal ); + push( @address, $Etat_Province ) if $Etat_Province ; + push( @address, $Pays, ) if $Pays ; + + + my $clientAdrA = shift( @address ) || '' ; + my $clientAdrB = shift( @address ) || '' ; + my $clientAdrC = shift( @address ) || '' ; + my $clientAdrD = shift( @address ) || '' ; + my $clientAdrE = shift( @address ) || '' ; + my $clientAdrF = shift( @address ) || '' ; + +$addr = " +[$clientAdrA] +[$clientAdrB] +[$clientAdrC] +[$clientAdrD] +[$clientAdrE] +[$clientAdrF] +"; + #print $addr ; + + return( + $clientAdrA, + $clientAdrB, + $clientAdrC, + $clientAdrD, + $clientAdrE, + $clientAdrF, + ) ; +} + + +sub half { + my $string = shift ; + my $half = int( lenght( $string ) / 2 ) ; + # TO BE DONE + +} + +sub tests_half { + my( $aa, $bb ) = half( 'aa bb' ) ; + ok( 'aa' eq $aa, 'half: aa' ) ; + ok( 'bb' eq $bb, 'half: bb' ) ; +} + +sub cut { + my $string = shift ; + my $offset = shift ; + + return( $string, '' ) if length( $string ) < $offset ; + my $first = substr( $string, 0, $offset ) ; + my $last = substr( $string, $offset ) ; + return( $first, $last ) ; +} + +sub tests_cut { + my( $aa, $bb ) = cut("123456789", 4 ) ; + ok( '1234' eq $aa, 'cut 123456789 4 => first 1234' ) ; + ok( '56789' eq $bb, 'cut 123456789 4 => last 56789' ) ; +} diff --git a/W/paypal_reply/paypal_build_invoices b/W/paypal_reply/paypal_build_invoices index d6f7159..a3a24f5 100755 --- a/W/paypal_reply/paypal_build_invoices +++ b/W/paypal_reply/paypal_build_invoices @@ -1,6 +1,6 @@ #!/bin/sh -# $Id: paypal_build_invoices,v 1.40 2012/10/03 14:29:07 gilles Exp gilles $ +# $Id: paypal_build_invoices,v 1.43 2012/12/15 00:15:56 gilles Exp gilles $ # usage: sh paypal_build_invoices /g/var/paypal_invoices/???? @@ -30,7 +30,9 @@ cp /home/gilles/public_html/AGIL/factures/000/facture_imapsync-000.tex /g/var/pa #/g/public_html/imapsync/W/paypal_reply/paypal_bilan --write_invoices --first_in 1824 /g/paypal/paypal_2012_07_complet.csv #/g/public_html/imapsync/W/paypal_reply/paypal_bilan --write_invoices --first_in 1891 /g/paypal/paypal_2012_08_complet.csv #/g/public_html/imapsync/W/paypal_reply/paypal_bilan --write_invoices --first_in 1963 /g/paypal/paypal_2012_09_complet.csv -/g/public_html/imapsync/W/paypal_reply/paypal_bilan --write_invoices --first_in 2047 /g/paypal/paypal_2012_10_complet.csv +#/g/public_html/imapsync/W/paypal_reply/paypal_bilan --write_invoices --first_in 2047 /g/paypal/paypal_2012_10_complet.csv +#/g/public_html/imapsync/W/paypal_reply/paypal_bilan --write_invoices --first_in 2133 /g/paypal/paypal_2012_11_complet.csv +/g/public_html/imapsync/W/paypal_reply/paypal_bilan --write_invoices --first_in 2224 /g/paypal/paypal_2012_12_complet.csv : /g/public_html/imapsync/W/paypal_reply/paypal_bilan --first_in 147 /g/paypal/paypal_2010_11_complet.csv @@ -56,22 +58,23 @@ cp /home/gilles/public_html/AGIL/factures/000/facture_imapsync-000.tex /g/var/pa : /g/public_html/imapsync/W/paypal_reply/paypal_bilan --first_in 1824 /g/paypal/paypal_2012_07_complet.csv : /g/public_html/imapsync/W/paypal_reply/paypal_bilan --first_in 1891 /g/paypal/paypal_2012_08_complet.csv : /g/public_html/imapsync/W/paypal_reply/paypal_bilan --first_in 1963 /g/paypal/paypal_2012_09_complet.csv -set -x : /g/public_html/imapsync/W/paypal_reply/paypal_bilan --first_in 2047 /g/paypal/paypal_2012_10_complet.csv - +set -x +: /g/public_html/imapsync/W/paypal_reply/paypal_bilan --first_in 2133 /g/paypal/paypal_2012_11_complet.csv +: /g/public_html/imapsync/W/paypal_reply/paypal_bilan --first_in 2224 /g/paypal/paypal_2012_12_complet.csv set +x # La totale : || /g/public_html/imapsync/W/paypal_reply/paypal_bilan --bnc --debug \ - --first_in 147 --avoid_numbers '292 293 643 644 731 732 1093 1330 1331 1332 1333 1334 1652 1653' \ + --first_in 147 --avoid_numbers '292 293 643 644 731 732 1093 1330 1331 1332 1333 1334 1652 1653 2131 2132' \ /g/paypal/paypal_201?_??_complet.csv : || /g/public_html/imapsync/W/paypal_reply/paypal_bilan \ - --first_in 147 --avoid_numbers '292 293 643 644 731 732 1093 1330 1331 1332 1333 1334 1652 1653' \ + --first_in 147 --avoid_numbers '292 293 643 644 731 732 1093 1330 1331 1332 1333 1334 1652 1653 2131 2132' \ /g/paypal/paypal_201?_??_complet.csv -echo 'sh paypal_build_invoices /g/var/paypal_invoices/1???' +echo 'sh paypal_build_invoices /g/var/paypal_invoices/2???' # USD de 147 à 340 # EUR de 341 à ... diff --git a/W/paypal_reply/paypal_send_invoices b/W/paypal_reply/paypal_send_invoices index e698111..1fc29db 100755 --- a/W/paypal_reply/paypal_send_invoices +++ b/W/paypal_reply/paypal_send_invoices @@ -47,8 +47,13 @@ send_invoice() { } } -echo $0 '/g/var/paypal_invoices/99?' +echo $0 '/g/var/paypal_invoices/2???' for d in "$@"; do ( send_invoice "$d" ) done + +echo ==== Saving to ks +rsync -avHz -P /g/var/paypal_invoices/ \ + imapsync@ks.lamiral.info:var/paypal_invoices + diff --git a/W/test.bat b/W/test.bat index 5f2fbdc..79656a3 100644 --- a/W/test.bat +++ b/W/test.bat @@ -1,10 +1,10 @@ -REM $Id: test.bat,v 1.9 2011/02/21 02:14:35 gilles Exp gilles $ +REM $Id: test.bat,v 1.10 2012/12/22 20:00:12 gilles Exp gilles $ cd C:\msys\1.0\home\Admin\imapsync perl -mMail::IMAPClient -mDigest::MD5 -mTerm::ReadKey -mIO::Socket::SSL -mDate::Manip -mFile::Spec -mDigest::HMAC_MD5 -e '' -perl ./imapsync +perl ./imapsync perl ./imapsync --host1 p --user1 tata --passfile1 secret.tata --host2 p --user2 titi --passfile2 secret.titi --delete2 --expunge2 perl ./imapsync --host1 p --user1 tata --passfile1 secret.tata --host2 p --user2 titi --passfile2 secret.titi --delete2 --expunge2 --folder INBOX --nofoldersizes perl ./imapsync --host1 p --user1 tata --passfile1 secret.tata --host2 p --user2 titi --passfile2 secret.titi --delete2 --expunge2 --folder INBOX --nofoldersizes --usecache diff --git a/W/test2.bat b/W/test2.bat index 735b459..f1a7d90 100644 --- a/W/test2.bat +++ b/W/test2.bat @@ -1,5 +1,6 @@ -REM $Id: test2.bat,v 1.11 2012/10/05 09:15:55 gilles Exp gilles $ +REM $Id: test2.bat,v 1.14 2012/12/24 02:25:34 gilles Exp gilles $ +REM cd C:\msys\1.0\home\Admin\imapsync REM perl ./imapsync --host1 p --user1 tata --passfile1 secret.tata --host2 p --user2 titi --passfile2 secret.titi --delete2 --expunge2 --folder INBOX @@ -38,6 +39,25 @@ REM perl ./imapsync --host1 p --user1 tata --passfile1 secret.tata ^ REM --host2 imap.gmail.com --ssl2 --user2 gilles.lamiral@gmail.com --passfile2 secret.gilles_gmail ^ REM --usecache --nofoldersizes --folder INBOX --regextrans2 "s(INBOX)([Gmail]/te*st)" -perl ./imapsync --host1 imap.gmail.com --port1 993 --ssl1 --host2 imap.bigs.dk --justconnect +REM perl ./imapsync --host1 imap.gmail.com --port1 993 --ssl1 --host2 imap.bigs.dk --justconnect -imapsync.exe --host1 imap.gmail.com --port1 993 --ssl1 --host2 imap.bigs.dk --justconnect +REM imapsync.exe --host1 imap.gmail.com --port1 993 --ssl1 --host2 imap.bigs.dk --justconnect + +REM @echo off + +DATE /t +TIME /t + +FOR /f "tokens=1-4 delims=-/: " %%a IN ('DATE /t') DO (SET mydate=%%c_%%a_%%b_%%d) +FOR /f "tokens=1-2 delims=-/: " %%a IN ('TIME /t') DO (SET mytime=%%a_%%b) +ECHO %mydate%_%mytime% + +if not exist LOG mkdir LOG +FOR /F "tokens=1,2,3,4 delims=; eol=#" %%G IN (file.txt) DO ECHO syncing to user %%I & imapsync ^ + --host1 imap.side1.org --user1 %%G --password1 %%H ^ + --host2 imap.side2.org --user2 %%I --password2 %%J ^ + > LOG\log_%%I_%mydate%_%mytime%.txt 2>&1 + +ECHO Loop finished +ECHO log files are in LOG directory +PAUSE diff --git a/W/test_exe_2.bat b/W/test_exe_2.bat index 56a4555..38f1c74 100644 --- a/W/test_exe_2.bat +++ b/W/test_exe_2.bat @@ -1,6 +1,6 @@ -REM - -cd C:\msys\1.0\home\Admin\imapsync - +REM + +cd C:\msys\1.0\home\Admin\imapsync + REM imapsync.exe \ --host1 p --user1 toto --passfile1 secret.toto \ --host2 p --user2 titi --passfile2 secret.titi .\imapsync.exe \ --host1 p --user1 tata --passfile1 secret.tata \ --host2 p --user2 titi --passfile2 secret.titi diff --git a/examples/.htaccess b/examples/.htaccess new file mode 100644 index 0000000..5a4e7f7 --- /dev/null +++ b/examples/.htaccess @@ -0,0 +1,4 @@ + +AddType text/plain .bat .sh + + diff --git a/examples/file.txt b/examples/file.txt index fcd8809..5cb908b 100644 --- a/examples/file.txt +++ b/examples/file.txt @@ -1,22 +1,9 @@ # Example file.txt for imapsync massive migration. # -# ==== Windows ==== -# Thanks to http://ss64.com/nt/for_f.html for -# the Windows example of a for loop -# -# This file can be used on Windows with the following line in a batch -# FOR /F "tokens=1,2,3,4 delims=; eol=#" %%G IN (file.txt) DO imapsync --host1 imap.truc.org --user1 %%G --password1 %%H --host2 imap.trac.org --user2 %%I --password2 %%J -# -# A line beginning with # is a comment thanks to option Win32 eol=# -# Separator is character ; it can be changed by any character changing delims=; # Each line contains 4 columns, columns are parameters for --user1 --password1 --user2 --password2 +# Windows: see the script examples/sync_loop_windows.bat +# Unix: see the script examples/sync_loop_unix.sh # -# ==== Unix ==== -# This file can be used on Unix with the following line in a Bourne shell script -# { while IFS=';' read u1 p1 u2 p2; do imapsync --user1 "$u1" --password1 "$p1" --user2 "$u2" --password2 "$p2" ... ; done ; } < file.txt -# -# Separator is character ; it can be changed by any character changing IFS=';' -# Each line contains 4 columns, columns are parameters for --user1 --password1 --user2 --password2 # # Now the data example user001_1;password001_1;user001_2;password001_2 diff --git a/examples/imapsync_example.bat.txt b/examples/imapsync_example.bat similarity index 100% rename from examples/imapsync_example.bat.txt rename to examples/imapsync_example.bat diff --git a/examples/sync_loop_unix.sh b/examples/sync_loop_unix.sh new file mode 100644 index 0000000..fc7e098 --- /dev/null +++ b/examples/sync_loop_unix.sh @@ -0,0 +1,30 @@ +#!/bin/sh +# +# $Id: sync_loop_unix.sh,v 1.2 2012/12/23 08:02:46 gilles Exp gilles $ + +# Example for imapsync massive migration on Unix systems. +# +# Data is supposed to be in file.txt in the following format +#user001_1;password001_1;user001_2;password001_2 +#... +# Separator is character semi-colon ; it can be changed by any character changing IFS=';' +# Each data line contains 4 columns, columns are parameters for --user1 --password1 --user2 --password2 +# +# Replace "imap.side1.org" and "imap.side2.org" with your own hostname values + +# This loop will also create a log file called LOG/log_${u2}_$NOW.txt for each account transfer +# where u2 is just a variable containing the user2 account name, and NOW is the current date_time + +mkdir -p LOG + +{ while IFS=';' read u1 p1 u2 p2 + do + { echo "$u1" | egrep "^#" ; } > /dev/null && continue + NOW=`date +%Y_%m_%d_%H_%M_%S` + echo syncing to user "$u2" + imapsync --host1 imap.side1.org --user1 "$u1" --password1 "$p1" \ + --host2 imap.side2.org --user2 "$u2" --password2 "$p2" \ + > LOG/log_${u2}_$NOW.txt 2>&1 + done +} < file.txt + diff --git a/examples/sync_loop_windows.bat b/examples/sync_loop_windows.bat new file mode 100644 index 0000000..466bf68 --- /dev/null +++ b/examples/sync_loop_windows.bat @@ -0,0 +1,36 @@ +REM +REM $Id: sync_loop_windows.bat,v 1.4 2012/12/23 08:02:34 gilles Exp gilles $ +REM +REM imapsync massive sync example batch for Windows users +REM lines beginning with REM are just comments +REM +REM You have to rename this file from sync_loop_windows.bat.txt to sync_loop_windows.bat +REM in order to make it a batch command file that your system will recognize and execute. +REM +REM Replace "imap.side1.org" and "imap.side2.org" with your own values +REM +REM This loop will also create a log file called log_%%I.txt for each account transfer +REM where %%I is just a variable containing the user2 account name. +REM and %mydate%_%mytime% is date and time formatted for a filename. +REM Since "date /t" is localy dependent you may have to adapt mydate=%%c_%%a_%%b_%%d + + +REM @echo off + +DATE /t +TIME /t + +FOR /f "tokens=1-4 delims=-/: " %%a IN ('DATE /t') DO (SET mydate=%%c_%%a_%%b_%%d) +FOR /f "tokens=1-2 delims=-/: " %%a IN ('TIME /t') DO (SET mytime=%%a_%%b) +ECHO %mydate%_%mytime% + +if not exist LOG mkdir LOG +FOR /F "tokens=1,2,3,4 delims=; eol=#" %%G IN (file.txt) DO ECHO syncing to user %%I & imapsync ^ + --host1 imap.side1.org --user1 %%G --password1 %%H ^ + --host2 imap.side2.org --user2 %%I --password2 %%J ^ + > LOG\log_%%I_%mydate%_%mytime%.txt 2>&1 + + +ECHO Loop finished +ECHO log files are in LOG directory +PAUSE diff --git a/imapsync b/imapsync index d7110c2..a247c77 100755 --- a/imapsync +++ b/imapsync @@ -20,7 +20,7 @@ Synchronise mailboxes between two imap servers. Good at IMAP migration. More than 44 different IMAP server softwares supported with success. -$Revision: 1.516 $ +$Revision: 1.518 $ =head1 SYNOPSIS @@ -350,7 +350,7 @@ Failure stories reported with the following 3 imap servers: any IMAP email client. -Success stories reported with the following 44 imap servers +Success stories reported with the following 48 imap servers (software names are in alphabetic order): - 1und1 H mimap1 84498 [host1] @@ -369,6 +369,7 @@ Success stories reported with the following 44 imap servers 2.3-alpha (OSI Approved), 2.3.1, 2.3.7, 2.3.16 (http://asg.web.cmu.edu/cyrus/) - David Tobit V8 (proprietary Message system). + - Deerfield VisNetic MailServer 5.8.6 [host1] (http://www.deerfield.net/products/visnetic-mailserver/) - DBMail 1.2.1, 2.0.4, 2.0.9, 2.2rc1 (GPL) (http://www.dbmail.org/). 2.0.7 seems buggy. - Deerfield VisNetic MailServer 5.8.6 [host1] @@ -405,6 +406,7 @@ Success stories reported with the following 44 imap servers - Samsung Contact IMAP server 8.5.0 - Scalix v10.1, 10.0.1.3, 11.0.0.431, 11.4.6 - SmarterMail, Smarter Mail 5.0 Enterprise, Smarter Mail 5.5 [host1]. + - Softalk Workgroup Mail 7.6.4 [host1]. - SunONE Messaging server 5.2, 6.0 (SUN JES - Java Enterprise System) - Sun Java(tm) System Messaging Server 6.2-2.05, 6.2-7.05, 6.3 - Surgemail 3.6f5-5 @@ -515,7 +517,7 @@ Entries for imapsync: Feedback (good or bad) will often be welcome. -$Id: imapsync,v 1.516 2012/11/02 22:15:04 gilles Exp gilles $ +$Id: imapsync,v 1.518 2012/12/24 00:27:34 gilles Exp gilles $ =cut @@ -646,7 +648,7 @@ my( # global variables initialisation -$rcs = '$Id: imapsync,v 1.516 2012/11/02 22:15:04 gilles Exp gilles $ '; +$rcs = '$Id: imapsync,v 1.518 2012/12/24 00:27:34 gilles Exp gilles $ '; $total_bytes_transferred = 0; $total_bytes_skipped = 0; @@ -735,8 +737,8 @@ $relogin2 = defined( $relogin2 ) ? $relogin2 : 5 ; if ( $fast ) { # $useuid = 1 ; - $foldersizes = 0 ; - $foldersizesatend = 0 ; + # $foldersizes = 0 ; + # $foldersizesatend = 0 ; } # Activate --usecache if --useuid is set and no --nousecache @@ -747,6 +749,7 @@ $checkselectable = defined( $checkselectable ) ? $checkselectable : 1 ; $checkmessageexists = defined( $checkmessageexists ) ? $checkmessageexists : 1 ; $expungeaftereach = defined( $expungeaftereach ) ? $expungeaftereach : 1 ; $abletosearch = defined( $abletosearch ) ? $abletosearch : 1 ; +$checkmessageexists = 0 if ( not $abletosearch ) ; $showpasswords = defined( $showpasswords ) ? $showpasswords : 0 ; $fixslash2 = defined( $fixslash2 ) ? $fixslash2 : 1 ; @@ -1088,7 +1091,7 @@ foreach my $h1_fold (@h1_folders_all) { if ( $foldersizes ) { ( $h1_nb_msg_start, $h1_bytes_start ) = foldersizes( "Host1", $imap1, @h1_folders_wanted ) ; ( $h2_nb_msg_start, $h2_bytes_start ) = foldersizes( "Host2", $imap2, @h2_folders_from_1_wanted ) ; - sleep( 2 ) ; + $fast or sleep( 2 ) ; } @@ -1555,9 +1558,13 @@ sub sync_flags { } print "++++ End looping on each folder\n"; +$debug and print "Time: ", timenext(), " s\n"; + #print memory_consumption(); + if ( $foldersizesatend ) { + timenext() ; ( $h1_nb_msg_end, $h1_bytes_end ) = foldersizes( "Host1", $imap1, @h1_folders_wanted ) ; ( $h2_nb_msg_end, $h2_bytes_end ) = foldersizes( "Host2", $imap2, @h2_folders_from_1_wanted ) ; } @@ -1983,8 +1990,8 @@ sub banner_imapsync { my @argv_copy = @_; my $banner_imapsync = join("", '$RCSfile: imapsync,v $ ', - '$Revision: 1.516 $ ', - '$Date: 2012/11/02 22:15:04 $ ', + '$Revision: 1.518 $ ', + '$Date: 2012/12/24 00:27:34 $ ', "\n",localhost_info(), "\n", "Command line used:\n", "$0 ", command_line_nopassword(@argv_copy), "\n", @@ -3866,6 +3873,9 @@ sub parse_header_msg { # remove the first blanks (dbmail bug ?) $val =~ s/^\s*(.+)$/$1/; + # change tabulations to space (Gmail bug on with "Received:" on multilines) + $val =~ s/\t/ /g ; + # and uppercase header line # (dbmail and dovecot) @@ -3976,7 +3986,7 @@ sub check_last_release { } sub imapsync_version { - my $rcs = '$Id: imapsync,v 1.516 2012/11/02 22:15:04 gilles Exp gilles $ '; + my $rcs = '$Id: imapsync,v 1.518 2012/12/24 00:27:34 gilles Exp gilles $ '; $rcs =~ m/,v (\d+\.\d+)/; my $VERSION = ($1) ? $1: "UNKNOWN"; return($VERSION); diff --git a/index.shtml b/index.shtml index 97c23ff..7b9c368 100644 --- a/index.shtml +++ b/index.shtml @@ -5,7 +5,7 @@ Imapsync: an IMAP migration tool ( release <!--#exec cmd="cat ./VERSION"--> ) - + @@ -68,17 +68,22 @@ for 2 ways synchronizations.

Some numbers for 2011 and 2012

    -
  • Number of imapsync users per month: between 2 and 3 thousands users
  • -
  • Number of imapsync transfers between 3 and 25 millions mailboxes transfers per month, -total is 93 millions for 2011
  • +
  • Number of imapsync users per month: between 3000 and 4000 users +(34000 users a year)
  • + +
  • Number of imapsync transfers between +5 and 25 millions mailboxes transfers per month, +total is 93 millions for 2011, 90 millions for 2012.
  • +
  • Percentage between operating systems users running imapsync:
      -
    • Linux: 65 %
    • -
    • Win32: 18 %
    • -
    • Darwin: 11 %
    • -
    • FreeBSD: 6 %
    • -
    • Solaris: 0.4 %
    • -
    • OpenBSD: 0.05 %
    • +
    • Linux: 67 %
    • +
    • Win32: 16 %
    • +
    • Darwin: 9 %
    • +
    • FreeBSD: 7 %
    • +
    • Solaris: 0.3 %
    • +
    • OpenBSD: 0.03 %
    • +
    • Other: 0.67 %
  • Biggest user usage: about 21 millions of IMAP mailbox transfers (in one month)
  • @@ -97,7 +102,7 @@ total is 93 millions for 2011

    New features or bugfixes since previous releases:

    +
      +
    • 1.518
    • + +
    • Bug fix: When identtifying with header, change tabulations to spaces +(Gmail bug on with "Received:" on multilines).
    • +
    • Bug fix: Bugfix. Automatic --nocheckmessageexists when --noabletosearch is set.
    • +
    + +
    • 1.516
    • @@ -121,42 +135,57 @@ One difference at the start and one at the end. Useful to detect quickly a difference between host2 and host1. Need both --foldersizes and --foldersizesatend options (which are on by default). -
    • Usability: Added --foldersizesatend. It gets the folders sizes at the end of the whole transfer. +
    • Usability: Added --foldersizesatend. +It gets the folders sizes at the end of the whole transfer. Turned on by default (use --nofoldersizesatend to turn it off).
    • -
    • Enhancement: Added option --delete2duplicates; it deletes messages in host2 that are duplicates. +
    • Enhancement: Added option --delete2duplicates; +it deletes messages in host2 that are duplicates. --delete2duplicates is on when --delete2 is set unless --nodelete2duplicates is set too.
    • Usability: Added current date at the beginning of the run, useful when imapsync doesn't end properly or hasn't finished yet.
    • -
    • Enhancement: Added option --pidfilelocking; it aborts imapsync, when just launched, +
    • Enhancement: Added option --pidfilelocking; +it aborts imapsync, when just launched, in case another imapsync may be running. Turned off by default
    • -
    • Usability: Added option --showpasswords. it shows passwords on output instead of "MASKED". +
    • Usability: Added option --showpasswords. +it shows passwords on output instead of "MASKED". Turned off by default. -Useful to restart a run by reading the log or to see what happen with special characters. +Useful to restart a run by reading the log +or to see what happen with special characters.
    • -
    • Bug fix: Added option --fixslash2 to avoid the 'Invalid mailbox name' error. -It acts when --sep2 is not character / and --sep1 is character / and host1 folder name contains --sep2 characters. +
    • Bug fix: Added option --fixslash2 +to avoid the 'Invalid mailbox name' error. +It acts when --sep1 is character / and --sep2 is not character / +and host1 folder name contains --sep2 characters. Turned on by default (--nofixslash2 to unable it).
    • -
    • Enhancement: Added option --noabletosearch to allow the listing of messages without the imap "SEARCH ALL" command. -It's useful for playing with poor imap servers like Softalk 7.6.4 (8.6 is fine with SEARCH ALL).
    • - +
    • Enhancement: Added option --noabletosearch +to allow the listing of messages without the imap "SEARCH ALL" command. +It's useful for playing with poor imap servers like Softalk 7.6.4 +(8.6 is fine with SEARCH ALL).
    • 1.508
    • -
    • Usability: imapsync guesses and prints when it'll finish the transfer; added ETA after each copy (Estimated Time of Arrival)
    • -
    • Enhancement: Added --noexpungeaftereach to speedup --delete --expunge from Gmail.
    • -
    • Usability: Added Host1 or Host2 before "Nb messages" "Total size" with --foldersiszes (to facilitate parsing)
    • -
    • Bug fix: Previous fix about characters *|?:"<> to _ in cache path was not complete.
    • +
    • Usability: imapsync guesses and prints when it'll finish the transfer; +added ETA after each copy (Estimated Time of Arrival)
    • + +
    • Enhancement: Added --noexpungeaftereach +to speedup --delete --expunge from Gmail.
    • + +
    • Usability: Added Host1 or Host2 before "Nb messages" "Total size" +with --foldersiszes (to facilitate parsing)
    • + +
    • Bug fix: Previous fix about characters *|?:"<> to _ +in cache path was not complete.
    @@ -171,6 +200,7 @@ It's useful for playing with poor imap servers like Softalk 7.6.4 (8.6 is
    • 1.500
    • +
    • Enhancement: Added option --nocheckselectable to fix INBOX issue with Jana-server.
    • Bug fix: The cache system didn't work in Win32 (problem with \ transformation).
    • Bug fix: Check the return of touch calls for the cache.
    • @@ -180,8 +210,12 @@ It's useful for playing with poor imap servers like Softalk 7.6.4 (8.6 is
      • 1.484
      • -
      • Bug fix: Back to select() (read-write mode) instead of examine() (read-only mode in 1.468) on host1. Needed with --delete
      • -
      • Enhancement: Added option --exitwhenover option to avoid locking when transfers exceed maximum limit. + +
      • Bug fix: Back to select() (read-write mode) instead of examine() +(read-only mode in 1.468) on host1. Needed with --delete
      • + +
      • Enhancement: Added option --exitwhenover option to avoid locking +when transfers exceed maximum limit. See for example this Gmail constraint @@ -214,16 +254,24 @@ See for example Simple transfer on Windows

        -See imapsync_example.bat.txt batch file example -that you can easily adapt with your parameters (remove .txt extension in order to run it). +See imapsync_example.bat +batch file example that you can easily adapt with your parameters.

        -

        Massive transfers

        +

        Massive transfers (many mailboxes)

        -See file.txt example for batch massive migration -(many mailboxes) on Windows or Unix. +In order to migrate many mailboxes a good way is to use a loop over a csv +file containing only the data credentials. +A example of this file is file.txt, +it can be used by the two following command scripts.
        + +On Windows, see sync_loop_windows.bat +batch example.
        + +On Unix, see sync_loop_unix.sh +example.

        @@ -259,7 +307,8 @@ any Unix, Linux, Windows, or Mac OS operating system.

        Payment by Paypal account and credit card accepted.
        -Price 42 EUR is equal to around 50 USD, no problem to pay in USD (or any currency) via paypal: +Price 42 EUR is equal to around 50 USD, +no problem to pay in USD (or any currency) via paypal:

        @@ -274,7 +323,9 @@ Price 42 EUR is equal to around 50 USD, no problem to pay in USD (
        -Enter your VAT if you're a European professional (for accounting). It's 2 letters followed by 11 digits, for example mine is FR74429303332. +Enter your VAT +if you're a European professional (for accounting). +It's 2 letters followed by 11 digits, for example mine is FR74429303332.

        You will receive a download link just after the payment.
        You will also receive a gpg signed invoice within a few days by email.
        -Please give a delivery postal address where the invoice will be needed (your company for example), -since reedit is not easy (and forbidden by law). +Please give a delivery postal address where the invoice will be needed +(your company for example), since reedit is not easy (and forbidden by law).

        @@ -305,7 +356,8 @@ buying the latest win32 standalone imapsync.exe for 42 EUR

        Payment by Paypal account and credit card accepted.
        -Price 42 EUR is equal to around 50 USD, no problem to pay in USD (or any currency) via paypal: +Price 42 EUR is equal to around 50 USD, +no problem to pay in USD (or any currency) via paypal:

        @@ -319,7 +371,9 @@ Price 42 EUR is equal to around 50 USD, no problem to pay in USD (
        -Enter your VAT if you're a European professional (for accounting). It's 2 letters followed by 11 digits, for example mine is FR74429303332. +Enter your VAT +if you're a European professional (for accounting). +It's 2 letters followed by 11 digits, for example mine is FR74429303332.

        You will receive a download link just after the payment.
        You will also receive a gpg signed invoice within a few days by email.
        -Please give a delivery postal address where the invoice will be needed (your company for example), -since reedit is not easy (and forbidden by law). +Please give a delivery postal address where the invoice will be needed +(your company for example), since reedit is not easy (and forbidden by law).

        @@ -343,14 +397,17 @@ The build system for imapsync.exe is XP Pro SP2 on a Intel Celeron 400 MHz 256 M

        Buy full professional support for imapsync

        -

        You will be able to expose your issues by email or phone and we'll work together until complete success. +

        You will be able to expose your issues by email +or phone and we'll work together until complete success.

        -

        For 90 EUR buy imapsync full support done by the imapsync designer/developper. +

        For 90 EUR buy imapsync full support +done by the imapsync designer/developper.

        Payment by Paypal account and credit card accepted.
        -90 EUR is equal to around 110 USD, no problem to pay in USD (or any currency) with paypal: +90 EUR is equal to around 110 USD, +no problem to pay in USD (or any currency) with paypal:

        @@ -364,7 +421,9 @@ Payment by Paypal account and credit card accepted.

        -Enter your VAT if you're a European professional (for accounting). It's 2 letters followed by 11 digits, for example mine is FR74429303332. +Enter your VAT +if you're a European professional (for accounting). +It's 2 letters followed by 11 digits, for example mine is FR74429303332.
        VAT <

        You will also receive a gpg signed invoice within a few days by email.
        -Please give a delivery postal address where the invoice will be needed (your company for example), -since reedit is not easy (and forbidden by law). +Please give a delivery postal address where the invoice will be needed +(your company for example), since reedit is not easy (and forbidden by law).

        Documentation

        -

        Read the INSTALL file to know how to install imapsync on your system. +

        Read the INSTALL file +to know how to install imapsync on your system.

        -

        The README file has many tips to understand imapsync and succeed in your migration or backup. +

        The README file has many tips +to understand imapsync and succeed in your migration or backup.

        -

        The FAQ file presents Frequently Asked Questions (and not so frequently asked ones). +

        The FAQ file presents Frequently Asked Questions +(and not so frequently asked ones).

        -

        The ChangeLog to read what changed in details since 2001.

        +

        The ChangeLog +to read what changed in details since 2001.

        -

        The TODO file list what may be coded or done in the future. +

        The TODO file +lists what may be coded or done in the future.

        -

        All the people I thank are in the CREDITS file. +

        All the people I thank are in the +CREDITS file.

        What you can do with imapsync is listed in COPYING. @@ -464,10 +529,14 @@ Don't hesitate to have a try, I will help you and make efforts to switch them to

      • DBMail 0.9, 2.0.7 (GPL). But most other DBMail releases are supported (see below)
      • Imail 7.04 (maybe).
      • MailEnable 1.54 (Proprietary) but MailEnable 4.23 is supported.
      • -
      • (2011) MDaemon 12.0.3 as host2 but MDaemon is supported as host1. MDaemon is simply buggy with the APPEND IMAP command with any IMAP email client.
      • +
      • (2011) MDaemon 12.0.3 as host2 + but MDaemon is supported as host1. + MDaemon is simply buggy with the APPEND IMAP command with any IMAP email client. +
      -

      Now the long reported success stories list: 46 different imap server softwares supported!
      +

      Now the long reported success stories list: +48 different imap server softwares supported!
      [host1] means "source server" and [host2] means "destination server":

      @@ -539,6 +608,7 @@ Don't hesitate to have a try, I will help you and make efforts to switch them to
    • Samsung Contact IMAP server 8.5.0
    • Scalix v10.1, 10.0.1.3, 11.0.0.431, 11.4.6 (http://www.scalix.com/)
    • SmarterMail, Smarter Mail 5.0 Enterprise, Smarter Mail 5.5 [host1]. (http://www.smartertools.com/)
    • +
    • Softalk Workgroup Mail 7.6.4 [host1] (http://www.softalkltd.com/products/download_wm_v7.asp).
    • SunONE Messaging server 5.2, 6.0 (SUN JES - Java Enterprise System) (http://www.oracle.com/)
    • Sun Java(tm) System Messaging Server 6.2-2.05, 6.2-7.05, 6.3 (http://www.oracle.com/)
    • Surgemail 3.6f5-5 (http://netwinsite.com/surgemail/)
    • @@ -548,13 +618,12 @@ Don't hesitate to have a try, I will help you and make efforts to switch them to
    • VMS, Imap part of TCP/IP suite of VMS 7.3.2 (http://h71000.www7.hp.com/openvms/)
    • Yahoo [host1] (http://www.yahoo.com/)
    • Zimbra-IMAP 3.0.1 GA 160, 3.1.0 Build 279, 4.0.5, 4.5.2, 4.5.6, - Zimbra 5.0.24_GA_3356.RHEL4 [host1], 5.5, 6.x - (http://www.zimbra.com/)
    • + Zimbra 5.0.24_GA_3356.RHEL4 [host1], 5.5, 6.x + (http://www.zimbra.com/)

    Similar softwares

    -
    • imap_tools: http://www.athensfbc.com/imap_tools
    • offlineimap: https://github.com/nicolas33/offlineimap
    • @@ -616,7 +685,7 @@ alt="Viewable With Any Browser" /> This document last modified on -($Id: index.shtml,v 1.136 2012/11/03 00:46:00 gilles Exp gilles $) +($Id: index.shtml,v 1.141 2012/12/24 01:03:07 gilles Exp gilles $)

      diff --git a/tests.sh b/tests.sh index 16eceb7..089f2bd 100644 --- a/tests.sh +++ b/tests.sh @@ -1,6 +1,6 @@ #!/bin/sh -# $Id: tests.sh,v 1.205 2012/11/03 00:38:15 gilles Exp gilles $ +# $Id: tests.sh,v 1.209 2012/12/24 02:24:09 gilles Exp gilles $ # Example 1: # CMD_PERL='perl -I./Mail-IMAPClient-3.32/lib' sh -x tests.sh @@ -179,7 +179,6 @@ locallocal() { ll_nofoldersizes() { - can_send && sendtestmessage $CMD_PERL ./imapsync \ --host1 $HOST1 --user1 tata \ --passfile1 ../../var/pass/secret.tata \ @@ -188,6 +187,15 @@ ll_nofoldersizes() --nofoldersizes --folder INBOX } +ll_nofoldersizes_nofoldersizesatend() +{ + $CMD_PERL ./imapsync \ + --host1 $HOST1 --user1 tata \ + --passfile1 ../../var/pass/secret.tata \ + --host2 $HOST2 --user2 titi \ + --passfile2 ../../var/pass/secret.titi \ + --nofoldersizes --nofoldersizesatend --folder INBOX +} pidfile() { @@ -260,6 +268,15 @@ ll_authmech_PREAUTH() { +ll_unknow_option() { + ! $CMD_PERL ./imapsync \ + --host1 $HOST1 --user1 tata \ + --passfile1 ../../var/pass/secret.tata \ + --host2 $HOST2 --user2 titi \ + --passfile2 ../../var/pass/secret.titi \ + --folder INBOX --unknow_option +} + ll_timeout() { @@ -859,6 +876,18 @@ ll_search_FLAGGED() --search 'FLAGGED' --folder INBOX } +ll_search_NOT_DELETED() +{ + can_send && sendtestmessage + $CMD_PERL ./imapsync \ + --host1 $HOST1 --user1 tata \ + --passfile1 ../../var/pass/secret.tata \ + --host2 $HOST2 --user2 titi \ + --passfile2 ../../var/pass/secret.titi \ + --search 'NOT DELETED' --folder INBOX +} + + ll_search_SENTSINCE() { can_send && sendtestmessage @@ -1434,6 +1463,46 @@ ll_regex_flag4() echo 'sudo rm -f /home/vmail/titi/.yop.yap/cur/*' } +ll_regex_flag5() +{ + $CMD_PERL ./imapsync \ + --host1 $HOST1 --user1 tata \ + --passfile1 ../../var/pass/secret.tata \ + --host2 $HOST2 --user2 titi \ + --passfile2 ../../var/pass/secret.titi \ + --folder INBOX.yop.yap \ + --debugflags --regexflag "s/Answered/Flagged/g" + + echo 'rm -f /home/vmail/titi/.yop.yap/cur/*' +} + + +ll_regex_flag6_add_SEEN() +{ + $CMD_PERL ./imapsync \ + --host1 $HOST1 --user1 tata \ + --passfile1 ../../var/pass/secret.tata \ + --host2 $HOST2 --user2 titi \ + --passfile2 ../../var/pass/secret.titi \ + --folder INBOX.yop.yap \ + --debugflags --regexflag "s/(.*)/\$1 \\\\Seen/" + + echo 'rm -f /home/vmail/titi/.yop.yap/cur/*' +} + +ll_regex_flag7_add_SEEN() +{ + $CMD_PERL ./imapsync \ + --host1 $HOST1 --user1 tata \ + --passfile1 ../../var/pass/secret.tata \ + --host2 $HOST2 --user2 titi \ + --passfile2 ../../var/pass/secret.titi \ + --folder INBOX.yop.yap \ + --debugflags --regexflag 's/(.*)/$1 \\Seen/' + + echo 'rm -f /home/vmail/titi/.yop.yap/cur/*' +} + ll_regex_flag_keep_only() { @@ -1845,7 +1914,14 @@ xxxxx_gmail() { --user2 gilles.lamiral@gmail.com \ --passfile2 ../../var/pass/secret.gilles_gmail \ --nofoldersizes \ - --justfolders --regextrans2 's/ //g' --exclude 'INBOX.yop.YAP' --exclude Gmail + --regextrans2 's/ +$//g' --regextrans2 's# +/#/#g' \ + --exclude 'INBOX.yop.YAP' \ + --regextrans2 "s,^Messages envoy&AOk-s$,[Gmail]/Messages envoy&AOk-s," \ + --regextrans2 "s,^Sent$,[Gmail]/Sent Mail," \ + --folder 'INBOX.Messages envoy&AOk-s' \ + --folder 'INBOX.Sent' + +# --exclude Gmail } @@ -1874,10 +1950,24 @@ xxxxx_gmail_3() { --user2 gilles.lamiral@gmail.com \ --passfile2 ../../var/pass/secret.gilles_gmail \ --nofoldersizes \ - --folder INBOX.few_emails --debug \ - --regextrans2 's,few_emails,Gmail/Messages envoyes,' + --folder INBOX.few_emails --debug --useheader Message-ID --delete2 --dry } +xxxxx_gmail_3_Received() { + + ! ping -c1 imap.gmail.com || $CMD_PERL ./imapsync \ + --host1 $HOST2 \ + --user1 tata \ + --passfile1 ../../var/pass/secret.tata \ + --host2 imap.gmail.com \ + --ssl2 \ + --user2 gilles.lamiral@gmail.com \ + --passfile2 ../../var/pass/secret.gilles_gmail \ + --nofoldersizes \ + --folder INBOX.few_emails --debug --useheader Received --delete2 --dry +} + + xxxxx_gmail_4_Sent() { ! ping -c1 imap.gmail.com || $CMD_PERL ./imapsync \ @@ -2969,8 +3059,8 @@ dprof_bigmail() mandatory_tests=' no_args -option_version -option_tests +option_version +option_tests option_tests_debug option_bad_delete2 passwords_masked @@ -2988,6 +3078,7 @@ gmail gmail_gmail gmail_gmail2 yahoo_xxxx +ll_unknow_option ll_ask_password ll_bug_folder_name_with_blank ll_timeout