#!/bin/bash # config file currently called ~/.mailmirror.conf # all config info now resides there, read it and configure it appropriately # for your needs . ~/.mailmirror.conf # Debugging setup # uncomment the line below to debug this script # set -x # comment this line out if you don't want to follow the list of # mailboxes being linked Verbose=yes # History info (since I started recording it, that is...) # 3.4, pldg, make default mailbox (mail) be on the dir title folder # for schemes that support this (plain hierarchy won't) # 3.3, pldg, 20060725, trying to port Evolution support to # 2.x family # thunderbird 2, evolution 2, kmail 4 all work ok # 3.2, pldg 20030223, created a config file, i.e. # splitted configuration info from shell code # 3.1.1, pldg 200210141315, just a cleaning of code and comments # 3.1, pldg 200206231705, first fully functional version # Variable post-processing section # Not to be edited by the user. # Be sure all dirs are absolute pathnames for i in OrigDir MirrorDir MainDir do echo "${!i}" | grep ^/ >/dev/null if [ ! "$?" = "0" ]; then echo "${!i} is not an absolute pathname! Bye..."; exit 1 fi done for i in $ExclusiveDirs $IncludeDirs $ExcludeDirs do echo "$i" | grep ^/ >/dev/null if [ ! "$?" = "0" ]; then echo "$i is not an absolute pathname! Bye..."; exit 1 fi done # Manipulate ExcludeDirs for proper `grep' syntax as ExcludeDirsGrep # `MirrorDir*' don't need to be excluded since they're removed early # on mailmirror's execution, to be then recreated. unset i ExcludeDirsGrep for i in $ExcludeDirs do ExcludeDirsGrep="$ExcludeDirsGrep -e $i " done # Manipulate MailboxNames for proper "grep" syntax as MailboxNamesGrep unset i MailboxNamesGrep for i in $MailboxNames do MailboxNamesGrep="$MailboxNamesGrep -e /$i\$ " done # Manipulate MailboxExtensions for proper "grep" syntax as # MailboxExtensionsGrep unset i MailboxExtensionsGrep for i in $MailboxExtensions do MailboxExtensionsGrep="$MailboxExtensionsGrep -e \\$i\$ " done # Manipulate ExcludeDirNames for proper "grep" syntax as ExcludeDirNamesGrep unset i ExcludeDirNamesGrep for i in $ExcludeDirNames do ExcludeDirNamesGrep="$ExcludeDirNamesGrep -e /$i/ " done # End of variable post-processing section # Start of code for real work # Mail Reader hierarchy-specific section DoHierarchy () { [ -d "${MirrorDirHierarchy}${1%/*}" ] ||\ mkdir -p "${MirrorDirHierarchy}${1%/*}" ln -s "${OrigDir}$1" "${MirrorDirHierarchy}$1" } DoThunderbird () { WorkPath="$1" unset BuildPath while true; do Name=`echo "${WorkPath}" | cut -d'/' -f2` WorkPath="${WorkPath#/${Name}}" echo "$WorkPath" | grep / >/dev/null # Is there a "/" yet? if [ "$?" = "0" ]; then touch "${MirrorDirThunderbird}${BuildPath}/${Name}" BuildPath="${BuildPath}/${Name}.sbd" [ -d "${MirrorDirThunderbird}${BuildPath}" ] ||\ mkdir "${MirrorDirThunderbird}${BuildPath}" else # All auxiliary dirs processed, now do the link # the usual default mailbox name (mail) will be linked to the # name of the parent dir if [ ${Name} == $MailboxNames ]; then # remove previously created empty file rm "${MirrorDirThunderbird}${BuildPath%.sbd}" ln -s "${OrigDir}$1" "${MirrorDirThunderbird}${BuildPath%.sbd}" break fi # mailboxes with the usual default extension will be linked to # their names stripped off of the extension if [ ${Name##*.} == ${MailboxExtensions#.} ]; then ln -s "${OrigDir}$1" "${MirrorDirThunderbird}${BuildPath}/${Name%${MailboxExtensions}}" break fi unset i # remaining, non-default mailbox names ln -s "${OrigDir}$1" "${MirrorDirThunderbird}${BuildPath}/${Name}" break fi done } DoKMail () { WorkPath="$1" unset BuildPath BuildPath2 Name2 while true; do Name=`echo "${WorkPath}" | cut -d'/' -f2` WorkPath="${WorkPath#/${Name}}" echo "$WorkPath" | grep / >/dev/null # Is there a "/" yet? if [ "$?" = "0" ]; then touch "${MirrorDirKMail}${BuildPath}/${Name}" BuildPath="${BuildPath}/.${Name}.directory" [ -d "${MirrorDirKMail}${BuildPath}" ] ||\ mkdir "${MirrorDirKMail}${BuildPath}" else # All auxiliary dirs processed, now do the link # the usual default mailbox name (mail) will be linked to the # name of the parent dir if [ ${Name} == $MailboxNames ]; then # remove previously created empty file BuildPath2="${BuildPath%.directory}" Name2="${BuildPath2##*/}" rm "${MirrorDirKMail}${BuildPath2%/*}/${Name2#.}" ln -s "${OrigDir}$1" "${MirrorDirKMail}${BuildPath2%/*}/${Name2#.}" break fi # mailboxes with the usual default extension will be linked to # their names stripped off of the extension if [ ${Name} ]; then ln -s "${OrigDir}$1" "${MirrorDirKMail}${BuildPath}/${Name%${MailboxExtensions}}" break fi unset i # remaining, non-default mailbox names ln -s "${OrigDir}$1" "${MirrorDirKMail}${BuildPath}/${Name}" break fi done } DoEvolution2 () { WorkPath="$1" unset BuildPath while true; do Name=`echo "${WorkPath}" | cut -d'/' -f2` WorkPath="${WorkPath#/${Name}}" echo "$WorkPath" | grep / >/dev/null # Is there a "/" yet? if [ "$?" = "0" ]; then touch "${MirrorDirEvolution2}${BuildPath}/${Name}" BuildPath="${BuildPath}/${Name}.sbd" [ -d "${MirrorDirEvolution2}${BuildPath}" ] ||\ mkdir "${MirrorDirEvolution2}${BuildPath}" else # All auxiliary dirs processed, now do the link # the usual default mailbox name (mail) will be linked to the # name of the parent dir if [ ${Name} == $MailboxNames ]; then # remove previously created empty file rm "${MirrorDirEvolution2}${BuildPath%.sbd}" ln -s "${OrigDir}$1" "${MirrorDirEvolution2}${BuildPath%.sbd}" break fi # mailboxes with the usual default extension will be linked to # their names stripped off of the extension if [ ${Name##*.} == ${MailboxExtensions#.} ]; then ln -s "${OrigDir}$1" "${MirrorDirEvolution2}${BuildPath}/${Name%${MailboxExtensions}}" break fi unset i # remaining, non-default mailbox names ln -s "${OrigDir}$1" "${MirrorDirEvolution2}${BuildPath}/${Name}" break fi done } # End of Mail Reader hierarchy-specific section # Processing of a single pathname, for all kinds of hierarchy ProcessPath () { # no longer needed, FullBuild does it better. #cat /dev/null >~/.mailmirror.log while true; do read Path if [ ! "$?" = "0" ]; then break fi [ "$Verbose" = "yes" ] && echo "Doing file ${Path#/}" RelativePath=${Path#${OrigDir}} DoHierarchy "$RelativePath" DoThunderbird "$RelativePath" DoKMail "$RelativePath" DoEvolution2 "$RelativePath" echo "$Path" >>~/.mailmirror.log done } # Initial mailboxes' preparation MainMailboxesLink () { # Make the links to Inbox and other main mailboxes # Main mailboxes: Inbox Drafts Sent Unsent\ Messages Trash # Needed for the following Mail Readers: Balsa (Hierarchy), # Mozilla/Netscape6, KMail and Evolution ln -s "${MainDir}/Inbox" "$MirrorDirHierarchy/inbox" ln -s "${MainDir}/Inbox" "$MirrorDirMozilla/Inbox" ln -s "${MainDir}/Inbox" "$MirrorDirThunderbird/Inbox" # KMail doesn't like a soft link for inbox, but is OK with a hard link ln "${MainDir}/Inbox" "$MirrorDirKMail/inbox" #mkdir "$MirrorDirEvolution/Inbox" #DefineEvolutionFolder "$MirrorDirEvolution/Inbox/folder-metadata.xml" #[ -f ~/evolution/local/Inbox/mbox ] && \ # mv ~/evolution/local/Inbox/mbox ~/evolution/local/Inbox/mbox.bak #[ -h ~/evolution/local/Inbox/mbox ] && \ # rm ~/evolution/local/Inbox/mbox #ln -s "${MainDir}/Inbox" ~/evolution/local/Inbox/mbox #ln -s "${MainDir}/Inbox" "$MirrorDirEvolution/Inbox/mbox" # Evolution2 stuff [ -f ~/.evolution/mail/local/Inbox ] && \ mv ~/.evolution/mail/local/Inbox ~/.evolution/mail/local/Inbox.bak [ -h ~/.evolution/mail/local/Inbox ] && \ rm ~/.evolution/mail/local/Inbox ln -s "${MainDir}/Inbox" ~/.evolution/mail/local/Inbox ln -s "${MainDir}/Drafts" "$MirrorDirHierarchy/draftbox" ln -s "${MainDir}/Drafts" "$MirrorDirMozilla/Drafts" ln -s "${MainDir}/Drafts" "$MirrorDirThunderbird/Drafts" ln -s "${MainDir}/Drafts" "$MirrorDirKMail/drafts" #[ -f ~/evolution/local/Drafts/mbox ] && \ # mv ~/evolution/local/Drafts/mbox ~/evolution/local/Drafts/mbox.bak #[ -h ~/evolution/local/Drafts/mbox ] && \ # rm ~/evolution/local/Drafts/mbox #ln -s "$MainDir/Drafts" ~/evolution/local/Drafts/mbox # Evolution2 stuff [ -f ~/.evolution/mail/local/Drafts ] && \ mv ~/.evolution/mail/local/Drafts ~/.evolution/mail/local/Drafts.bak [ -h ~/.evolution/mail/local/Drafts ] && \ rm ~/.evolution/mail/local/Drafts ln -s "$MainDir/Drafts" ~/.evolution/mail/local/Drafts ln -s "${MainDir}/Sent" "$MirrorDirHierarchy/sentbox" ln -s "${MainDir}/Sent" "$MirrorDirMozilla/Sent" ln -s "${MainDir}/Sent" "$MirrorDirThunderbird/Sent" ln -s "${MainDir}/Sent" "$MirrorDirKMail/sent-mail" #[ -f ~/evolution/local/Sent/mbox ] && \ # mv ~/evolution/local/Sent/mbox ~/evolution/local/Sent/mbox.bak #[ -h ~/evolution/local/Sent/mbox ] && \ # rm ~/evolution/local/Sent/mbox #ln -s "$MainDir/Sent" ~/evolution/local/Sent/mbox # Evolution2 stuff [ -f ~/.evolution/mail/local/Sent ] && \ mv ~/.evolution/mail/local/Sent ~/.evolution/mail/local/Sent.bak [ -h ~/.evolution/mail/local/Sent ] && \ rm ~/.evolution/mail/local/Sent ln -s "$MainDir/Sent" ~/.evolution/mail/local/Sent ln -s "${MainDir}/Unsent\ Messages" "$MirrorDirHierarchy/outbox" ln -s "${MainDir}/Unsent\ Messages" "$MirrorDirMozilla/Unsent\ Messages" ln -s "${MainDir}/Unsent\ Messages" "$MirrorDirThunderbird/Unsent\ Messages" ln -s "${MainDir}/Unsent\ Messages" "$MirrorDirKMail/outbox" #[ -f ~/evolution/local/Outbox/mbox ] && \ # mv ~/evolution/local/Outbox/mbox ~/evolution/local/Outbox/mbox.bak #[ -h ~/evolution/local/Outbox/mbox ] && \ # rm ~/evolution/local/Outbox/mbox #ln -s "${MainDir}/Unsent\ Messages" ~/evolution/local/Outbox/mbox # Evolution2 stuff [ -f ~/.evolution/mail/local/Outbox ] && \ mv ~/.evolution/mail/local/Outbox ~/.evolution/mail/local/Outbox.bak [ -h ~/.evolution/mail/local/Outbox ] && \ rm ~/.evolution/mail/local/Outbox ln -s "${MainDir}/Unsent\ Messages" ~/.evolution/mail/local/Outbox ln -s "${MainDir}/Trash" "$MirrorDirHierarchy/trash" ln -s "${MainDir}/Trash" "$MirrorDirMozilla/Trash" ln -s "${MainDir}/Trash" "$MirrorDirThunderbird/Trash" ln -s "${MainDir}/Trash" "$MirrorDirKMail/trash" #[ -f ~/evolution/local/Trash/mbox ] && \ # mv ~/evolution/local/Trash/mbox ~/evolution/local/Trash/mbox.bak #[ -h ~/evolution/local/Trash/mbox ] && \ # rm ~/evolution/local/Trash/mbox #ln -s "$MainDir/Trash" ~/evolution/local/Trash/mbox # Evolution2 stuff [ -f ~/.evolution/mail/local/Trash ] && \ mv ~/.evolution/mail/local/Trash ~/.evolution/mail/local/Trash.bak [ -h ~/.evolution/mail/local/Trash ] && \ rm ~/.evolution/mail/local/Trash ln -s "$MainDir/Trash" ~/.evolution/mail/local/Trash # Fix base directory for Evolution #for i in $ExclusiveDirs #do # j=${i#$OrigDir/}; j=${j%%/*} # rm -rf ~/"evolution/local/$j" # ln -s "$MirrorDirEvolution/$j" ~/"evolution/local/$j" # rm -rf ~/".evolution/mail/local/$j" # ln -s "$MirrorDirEvolution2/$j" ~/".evolution/mail/local/$j" #done } # High-level function to process the whole mailbox hierarchies FullBuild () { # Build all types of hierarchies # create symbolic links in MirrorDir to mailboxes in OrigDir, # identified by MailboxNames and MailboxExtensions. # It builds a list of files from the `IncludeDirs' hierarchies and filters # out invisible filenames (dot) and files that belong to the `ExcludeDirs' # list of hierarchies (conveniently post processed), then proceeds # to find proper mailboxes (`MailboxNames' and `MailboxExtensions') from # the resulting list of files, which are then fed to the `ProcessPath' # for the mirroring process mv ~/.mailmirror.log ~/.mailmirror.log.bak >/dev/null rm -rf "$MirrorDirHierarchy" "$MirrorDirMozilla" "$MirrorDirKMail" \ "$MirrorDirThunderbird" \ "$MirrorDirEvolution" "$MirrorDirEvolution2" >/dev/null mkdir "$MirrorDirHierarchy" "$MirrorDirMozilla" "$MirrorDirKMail" \ "$MirrorDirThunderbird" \ "$MirrorDirEvolution" "$MirrorDirEvolution2" # find $ExclusiveDirs \ -type f \ | fgrep -v -e '/.' \ $ExcludeDirNamesGrep \ | ProcessPath #echo MailboxNamesGrep=$MailboxNamesGrep #echo MailboxExtensionsGrep=$MailboxExtensionsGrep find $IncludeDirs \ -type f \ | fgrep -v -e '/.' \ $ExcludeDirNamesGrep \ $ExcludeDirsGrep \ | egrep $MailboxNamesGrep $MailboxExtensionsGrep \ | ProcessPath # >~/.mailmirror.log # debugging purposes only... # MainMailboxesLink } # High-level function to add a single mailbox to the mailbox hierarchy # Very useful when you don't want to wait for a full build, which in # my case is always. Ever since this script stabilized I never rebuilt # my hierarchy in full. Today I'll do it mainly because I'm in an # expunge mood (I'm subject to periodical bursts of sudden # organizational urge...) AddMailbox () { #set -x # Build mirror for a single mailbox, # create symbolic links in MirrorDir to mailboxes in OrigDir, # identified by MailboxNames and MailboxExtensions. read Path #rm ~/.mailmirror.log >/dev/null for i in $MirrorDirHierarchy $MirrorDirKMail $MirrorDirThunderbird \ $MirrorDirEvolution2; do if [ ! -d "${i}" ]; then echo "Can't find directory ${i}"; exit 1 fi done echo "$Path" | ProcessPath #set +x } Usage () { echo "Mailmirror, a tool for the compatible, simultaneous use of" echo "several Mail Readers. Usage:" echo "-r" echo $'\t'"Recreate all Mirror hierarchies (may take some time...)" echo "-a full_pathname_of_a_mailbox" echo $'\t'"Add a single Mailbox to the Mirror structures" } # Main block, parse arguments case "$#" in 1) if [ "$1" = "-r" ]; then FullBuild; exit 0 else Usage; exit 1 fi ;; 2) if [ "$1" = "-a" ]; then if [ -f "$2" ]; then echo $2 | grep ^/ >/dev/null if [ "$?" = "0" ]; then echo "$2" | AddMailbox exit 0 else Usage; exit 1 fi else Usage; exit 1 fi fi ;; *) Usage; exit 1 esac # 1- List of plain folder hierarchy structure Mail readers # Netscape4, Balsa, Pine? # 2- Details of complex mail folder hierarchy structure # Usually they also need an initial mail folder root dir customization, # done directly from the application # Base example: a/b/c # Mozilla (Netscape6): # each subdir `dir' needs a `dir.sbd' symbolic link # a.sbd -> a; a/b.sbd -> a/b; a/b/c.sbd -> a/b/c (correct links, that is...) # Thunderbird: # Similar do KMail below, only the subdir is called a.sbd # KMail # each logical subdir `dir' must actually be a file (empty or not, since # it can also be a mail folder), and the directory structure is built by # creating a `.dir.directory' dir # file a and mailbox projectA, dir .a.directory; # file .a.directory/b and mailbox projectX, dir .a.directory/.b.directory ... # Evolution # each subdir `dir' needs to be inside a `subfolders' subdir, # inside its parent dir # a/subfolders/b/subfolders/c # the `a' mail folder itself is actually a/mbox (empty or not) and # is not essential for building the hierarchy, # but a/folder-metadata.xml needs to be copied from a valid evolution folder # Here's its contents: # # # mail # # # Evolution 2 # each subdir `dir' needs a `dir.sbd' symbolic link # a.sbd -> a; a/b.sbd -> a/b; a/b/c.sbd -> a/b/c (correct links, that is...)