No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

smd-common 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. # Released under the terms of GPLv3 or at your option any later version.
  2. # No warranties.
  3. # Copyright Enrico Tassi <gares@fettunta.org>
  4. # Common stuff for smd-pull and smd-push
  5. # Convention:
  6. # - uppercase variables are global
  7. # - lowercase variables are local
  8. # - function arguments are documented assigning to local variable with
  9. # a decent name positional arguments
  10. ### Housekeeping ###
  11. __TOREMOVE=""
  12. __TOKILL=""
  13. atexit_rm() {
  14. local path="$1"
  15. __TOREMOVE="$__TOREMOVE $path"
  16. }
  17. atexit_kill() {
  18. local pid="$1"
  19. __TOKILL="$__TOKILL $pid"
  20. }
  21. gc_mktemp() {
  22. local tmp=`mktemp -q /tmp/smd.XXXXXXXXXX`
  23. atexit_rm $tmp
  24. RC="$tmp"
  25. }
  26. __cleanup() {
  27. rm -f $__TOREMOVE
  28. for p in $__TOKILL; do
  29. kill $p 2>/dev/null || true
  30. done
  31. }
  32. trap __cleanup "EXIT"
  33. ### Variables setup and sanity checks ###
  34. assert_executable() {
  35. if type $1 >/dev/null; then
  36. :
  37. else
  38. echo $1 not found, please install it or fix the paths
  39. echo PATH=$PATH
  40. echo type $1: `type $1`
  41. exit 1
  42. fi
  43. }
  44. init() {
  45. if [ `echo $PREFIX | cut -c -1` = "@" ]; then
  46. SMDSERVER=./smd-server
  47. SMDCLIENT=./smd-client
  48. MDDIFF=./mddiff
  49. # in development mode we assume that on the remote host
  50. # the software is installed such that binaries are in $PATH
  51. REMOTESMDSERVER=smd-server
  52. REMOTESMDCLIENT=smd-client
  53. else
  54. SMDSERVER=$PREFIX/bin/smd-server
  55. SMDCLIENT=$PREFIX/bin/smd-client
  56. MDDIFF=$PREFIX/bin/mddiff
  57. REMOTESMDSERVER="$SMDSERVER"
  58. REMOTESMDCLIENT="$SMDCLIENT"
  59. fi
  60. H=$HOME
  61. CONFDIR=$H/.smd
  62. LOCKFILE=$CONFDIR/lock
  63. SHOWTAGS=0
  64. VERBOSE=0
  65. DRYRUN=0
  66. TEMPLATE_ONLY=0
  67. CONFFILE=""
  68. WORKAREA=$CONFDIR/workarea
  69. REPNAME=default
  70. CHILDSARGS=
  71. REMOTEEXCLUDE=
  72. LOCALEXCLUDE=
  73. SMDCLIENTOPTS=
  74. SMDSERVEROPTS=
  75. RENAMEDB=.smd/rename-db
  76. # default values for the configuration file
  77. DEBUG=false
  78. # external programs
  79. SSH="@SSH@"
  80. if [ `echo "$SSH" | cut -c -1` = "@" ]; then
  81. SSH=ssh
  82. echo "`basename $0` not installed, assuming secure shell client is $SSH"
  83. fi
  84. SED="@SED@"
  85. if [ `echo "$SED" | cut -c -1` = "@" ]; then
  86. SED=sed
  87. echo "`basename $0` not installed, assuming stream editor is $SED"
  88. fi
  89. # sanity checks for required binaries
  90. assert_executable $SED
  91. assert_executable $SSH
  92. assert_executable $MDDIFF
  93. assert_executable $SMDSERVER
  94. assert_executable $SMDCLIENT
  95. # setup of confdir
  96. $MDDIFF --mkdir-p $CONFDIR/
  97. $MDDIFF --mkdir-p $CONFDIR/log
  98. $MDDIFF --mkdir-p $CONFDIR/fifo
  99. $MDDIFF --mkdir-p $CONFDIR/hooks
  100. cat > $CONFDIR/hooks/README <<-EOT
  101. From version 0.9.14, smd-push and smd-pull can run user defined
  102. hooks before and after doing their job.
  103. Sample hooks are available in the source tarball under sample-hooks/.
  104. The invocation of hooks is documented in the main README file.
  105. EOT
  106. $MDDIFF --mkdir-p $CONFDIR/hooks/pre-pull.d
  107. $MDDIFF --mkdir-p $CONFDIR/hooks/pre-push.d
  108. $MDDIFF --mkdir-p $CONFDIR/hooks/post-pull.d
  109. $MDDIFF --mkdir-p $CONFDIR/hooks/post-push.d
  110. CRUFT=`find $CONFDIR/workarea ! -type d -a ! -type l 2> /dev/null || true`
  111. if [ ! -z "$CRUFT" ]; then
  112. echo "Some files are left in $CONFDIR/workarea"
  113. echo "This is an internal error. Please report this inconvenience"
  114. echo "and examine the content of these files, they may be of value."
  115. echo
  116. echo $CRUFT
  117. exit 1
  118. fi
  119. rm -rf $CONFDIR/workarea
  120. $MDDIFF --mkdir-p $CONFDIR/workarea
  121. }
  122. is_absolute() {
  123. case "$1" in
  124. /*) return 0 ;;
  125. *) return 1 ;;
  126. esac
  127. }
  128. resolve_translator(){
  129. local T=${1%% *}
  130. if [ ! -z "$T" ]; then
  131. if is_absolute "$1"; then
  132. RC="$1"
  133. elif `type "$HOME/$T" >/dev/null 2>&1`; then
  134. RC="$HOME/$1"
  135. elif `type "$T" >/dev/null 2>&1`; then
  136. RC="$1"
  137. else
  138. echo "Unable to find the given translator: $T"
  139. echo "It is not an absolute path"
  140. echo "It is not in \$HOME=$HOME"
  141. echo "It is not in \$PATH=$PATH"
  142. if [ $showtags = 1 ]; then
  143. echo "$REPNAME: $localprog@$localhost: TAGS: error::context(conf) probable-cause(translator-not-found) human-intervention(necessary)"
  144. fi
  145. exit 1
  146. fi
  147. else
  148. RC="cat"
  149. fi
  150. }
  151. setup_workarea(){
  152. gc_mktemp
  153. local TMP_FIND="$RC"
  154. gc_mktemp
  155. local TMP_FIND_ERR="$RC"
  156. $MDDIFF $LOCALEXCLUDE -l $MAILBOX_LOCAL >$TMP_FIND 2>$TMP_FIND_ERR
  157. if [ ! $? -eq 0 ]; then
  158. echo "$MDDIFF gave an error while scanning $MAILBOX_LOCAL:"
  159. cat $TMP_FIND_ERR
  160. exit 1
  161. fi
  162. local FIFO_MKDIR="$CONFDIR/fifo/mkdir"
  163. [ -p "$FIFO_MKDIR" ] || $MDDIFF --mkfifo "$FIFO_MKDIR"
  164. local FIFO_MKDIRB="$CONFDIR/fifo/mkdir-back"
  165. [ -p "$FIFO_MKDIRB" ] || $MDDIFF --mkfifo "$FIFO_MKDIRB"
  166. $MDDIFF -s "$FIFO_MKDIR" > "$FIFO_MKDIRB" &
  167. local DIR_MAKER=$!
  168. atexit_kill $DIR_MAKER
  169. exec 6<$FIFO_MKDIRB
  170. exec 9>$FIFO_MKDIR
  171. gc_mktemp
  172. local TMP_T="$RC"
  173. local ERR=0
  174. eval "$TRANSLATOR_LR" <$TMP_FIND >$TMP_T || ERR=$?
  175. exec 7<$TMP_FIND
  176. exec 8<$TMP_T
  177. while read M <&7 && read TM <&8; do
  178. if [ $ERR -eq 1 -o "$TM" = "ERROR" ]; then
  179. echo "Error: translating $M"
  180. cat $TMP_T
  181. if [ $showtags = 1 ]; then
  182. echo "$REPNAME: $localprog@localhost: TAGS: error::context(workarea) probable-cause(bad-translator) human-intervention(necessary)"
  183. fi
  184. exit 1
  185. fi
  186. if [ $VERBOSE -eq 1 -a "$M" != "$TM" ]; then
  187. echo "translating:" $M "->" $TM
  188. fi
  189. if echo "$TM" | grep -q -e '\.\.'; then
  190. echo "Error: the translator returned a path containing .."
  191. exit 1
  192. fi
  193. echo "$HOME/$M" 1>&9
  194. echo ".smd/workarea/$TM" 1>&9
  195. read R <&6
  196. if [ "$R" != "OK" ]; then
  197. echo "$REPNAME: $localprog@localhost: TAGS: error::context(workarea) probable-cause(mddiff-s-error) human-intervention(necessary)"
  198. exit 1
  199. fi
  200. done
  201. exec 6<&-
  202. exec 7<&-
  203. exec 8<&-
  204. exec 9>&-
  205. wait $DIR_MAKER || ERR=1
  206. if [ $ERR -eq 1 ]; then
  207. echo "Error: creating symlinks"
  208. if [ $showtags = 1 ]; then
  209. echo "$REPNAME: $localprog@localhost: TAGS: error::context(workarea) probable-cause(fail-create-symlink) human-intervention(necessary)"
  210. fi
  211. exit 1
  212. fi
  213. }
  214. ### Command line argument parsing ###
  215. parse_args() {
  216. for arg in "$@"; do
  217. case $arg in
  218. -v|--verbose)
  219. VERBOSE=1
  220. SHOWTAGS=1
  221. CHILDSARGS="$CHILDSARGS -v"
  222. ;;
  223. -s|--show-tags)
  224. SHOWTAGS=1
  225. ;;
  226. -t|--template-only)
  227. TEMPLATE_ONLY=1
  228. ;;
  229. -d|--dry-run)
  230. DRYRUN=1
  231. CHILDSARGS="$CHILDSARGS -d"
  232. VERBOSE=1
  233. SHOWTAGS=1
  234. ;;
  235. -n|--no-delete)
  236. SMDSERVEROPTS="$SMDSERVEROPTS -n"
  237. ;;
  238. -*)
  239. cat <<-EOT
  240. usage: `basename $0` [options] [endpoint]
  241. Refer to the man page for `basename $0`
  242. EOT
  243. exit 1
  244. ;;
  245. *)
  246. REPNAME="$arg"
  247. ;;
  248. esac
  249. done
  250. CONFFILE=$CONFDIR/config.$REPNAME
  251. }
  252. ### Confdir setup ###
  253. myfakessh() {
  254. shift
  255. cd
  256. "$@"
  257. }
  258. read_conffile() {
  259. # backward compatibility code
  260. if [ ! -f $CONFFILE ] && \
  261. [ "$REPNAME" = "default" ] && \
  262. [ -f $CONFDIR/config ]; then
  263. # we import the old conffile
  264. echo "From version 0.9.4, configuration files are named"
  265. echo "$CONFDIR/config.\$FOO, where FOO is an optional argument"
  266. echo "to smd-pull/smd-push. The default value of FOO is 'default'."
  267. echo "I'm renaming $CONFDIR/config to $CONFFILE."
  268. mv $CONFDIR/config $CONFFILE
  269. fi
  270. if [ ! -f $CONFFILE ]; then
  271. cat > $CONFFILE <<- EOT
  272. # No config file found, this is a template. You want to edit it.
  273. # Host name to be used with ssh as the server (use ~/.ssh/config
  274. # for extra options). smd-pull will pull from this host, smd-push
  275. # will push to this host and use it as the id of the remote mailbox.
  276. #
  277. # You should create an alias within your ~/.ssh/config like the
  278. # following on:
  279. #
  280. # Host smd-server-foo
  281. # Compression yes
  282. # Hostname your.real.server.name
  283. # User you
  284. #
  285. SERVERNAME=smd-server-$REPNAME
  286. # Host name to be used as the client.
  287. # smd-pull will use this just as an id for the client. If you
  288. # plan to sync with multiple endpoints, you must use a different
  289. # client id for any of them, thus a pair localhostname-remotehostname
  290. # should be used
  291. #
  292. CLIENTNAME=`hostname`-$REPNAME
  293. # The mailbox to sync, in case the path is the same on both hosts.
  294. # The path MUST be relative to the home directory, use a symlink if
  295. # the mailbox is not rooted there. If these paths contain spaces,
  296. # they must be substituted with %20.
  297. #
  298. MAILBOX="Mail/"
  299. # Use different paths on the local and remote hosts
  300. #
  301. # Local and remote mailbox may differ in name, as well as their
  302. # sub directory/folder structure. In that case a translator must be
  303. # provided. A translator is a program that takes in input, as it
  304. # first and only argument, a directory name (ending in /cur or /new
  305. # or /tmp) and prints on stdout its translation. Refer to the
  306. # smd-config (5) manpage for more infos.
  307. #
  308. # MAILBOX_LOCAL="Mail/"
  309. # MAILBOX_REMOTE="OtherMail/"
  310. # TRANSLATOR_RL=command
  311. # TRANSLATOR_LR=command
  312. # Ignore some paths
  313. #
  314. # To exclude some paths from the synchronization you can specify
  315. # a space separated list of glob(7) expressions. Spaces in these
  316. # expressions must be replaced with %20.
  317. #
  318. # EXCLUDE="Mail/spam Mail/trash Mail/with%20spaces"
  319. #
  320. # If the local and remote mailbox differ in name or their
  321. # sub directory/folder structure you can specify different
  322. # excluded paths for the two endpoints.
  323. #
  324. # EXCLUDE_LOCAL="Mail/spam Mail/trash"
  325. # EXCLUDE_REMOTE="OtherMail/with%20spaces"
  326. # Local synchronization
  327. #
  328. # If the local and remote mailboxes are on the same host
  329. # the following option must be added to the configuration file:
  330. #
  331. # SMDCLIENTOPTS=-l
  332. # Avoid deletions
  333. #
  334. # In some cases, usually unidirectional synchronizations, one may want
  335. # to not propagate deletions. E.g. one keeps a slim working mailbox but
  336. # pushes to a backup mailbox to save every email.
  337. #
  338. # SMDSERVEROPTS=-n
  339. # If the local and remote mailboxes are on the same host
  340. # the following option must be added to the configuration file:
  341. #
  342. # SMDCLIENTOPTS=-l
  343. # Log client to server and server to client communication.
  344. #
  345. # This is useful only for debugging, since all network traffic
  346. # is dumped, including transmitted mails.
  347. #
  348. # DEBUG=true
  349. EOT
  350. echo No config file found: created a default one
  351. echo Please edit it: $CONFFILE
  352. if [ "$TEMPLATE_ONLY" = 1 ]; then
  353. exit 0
  354. else
  355. exit 1
  356. fi
  357. fi
  358. if [ "$TEMPLATE_ONLY" = 1 ]; then
  359. exit 0
  360. fi
  361. . $CONFFILE
  362. # sanityze
  363. MAILBOX="${MAILBOX%%/}"
  364. MAILBOX_LOCAL="${MAILBOX_LOCAL%%/}"
  365. MAILBOX_REMOTE="${MAILBOX_REMOTE%%/}"
  366. # default exclude
  367. if [ -z "$EXCLUDE_LOCAL" ]; then
  368. EXCLUDE_LOCAL="$EXCLUDE"
  369. fi
  370. if [ -z "$EXCLUDE_REMOTE" ]; then
  371. EXCLUDE_REMOTE="$EXCLUDE"
  372. fi
  373. for e in $EXCLUDE_LOCAL; do
  374. LOCALEXCLUDE="$LOCALEXCLUDE --exclude $e"
  375. done
  376. for e in $EXCLUDE_REMOTE; do
  377. REMOTEEXCLUDE="$REMOTEEXCLUDE --exclude $e"
  378. done
  379. # check for local synchronization
  380. if [ "$SERVERNAME" = "localhost" ]; then
  381. if echo "$SMDCLIENTOPTS" | grep -q -v -e "-l"; then
  382. echo "SERVERNAME is localhost but SMDCLIENTOPTS is not set."
  383. echo "Local synchronizations must set SMDCLIENTOPTS."
  384. else
  385. # no need to ssh
  386. SSH=myfakessh
  387. fi
  388. fi
  389. }
  390. ### Only one instance at a time please ###
  391. check_lockfile() {
  392. # could be relaxed to non related mailboxes/enpoints, but the test is
  393. # not straightforward
  394. if [ -f $LOCKFILE ]; then
  395. if ps -p `cat $LOCKFILE` 2> /dev/null | grep -E 'smd-(push|pull)'; then
  396. echo Already running.
  397. echo If this is not the case, remove $LOCKFILE by hand.
  398. echo "any: smd-pushpull@localhost: TAGS: error::context(locking) probable-cause(another-instance-is-running) human-intervention(necessary) suggested-actions(run(kill `cat $LOCKFILE`) run(rm $LOCKFILE))"
  399. exit 1
  400. else
  401. echo Found lockfile of a dead instance. Ignored.
  402. fi
  403. fi
  404. echo $$ > $LOCKFILE
  405. atexit_rm $LOCKFILE
  406. }
  407. ### Create all the needed pipes ###
  408. setup_plumbing() {
  409. CtL=$CONFDIR/fifo/c2l.$REPNAME
  410. LtC=$CONFDIR/fifo/l2c.$REPNAME
  411. LtS=$CONFDIR/fifo/l2s.$REPNAME
  412. StL=$CONFDIR/fifo/s2l.$REPNAME
  413. PRp=$CONFDIR/fifo/pr.$REPNAME
  414. [ -p $CtL ] || $MDDIFF --mkfifo $CtL
  415. [ -p $LtC ] || $MDDIFF --mkfifo $LtC
  416. [ -p $LtS ] || $MDDIFF --mkfifo $LtS
  417. [ -p $StL ] || $MDDIFF --mkfifo $StL
  418. [ -p $PRp ] || $MDDIFF --mkfifo $PRp
  419. }
  420. ### Logging ###
  421. mycat() {
  422. # like cat, but ignores arguments
  423. cat
  424. }
  425. myreporter() {
  426. tee -a $1 | grep --line-buffered ^PROGRESS: | sed 's?^PROGRESS: ??'
  427. }
  428. mysilentreporter() {
  429. cat >> $1
  430. }
  431. setup_logging() {
  432. CtS=$CONFDIR/log/c2s.$REPNAME.log
  433. StC=$CONFDIR/log/s2c.$REPNAME.log
  434. CL=$CONFDIR/log/client.$REPNAME.log
  435. SL=$CONFDIR/log/server.$REPNAME.log
  436. MITM=mycat
  437. if [ "$DEBUG" = "true" ]; then
  438. MITM=tee
  439. CHILDSARGS="$CHILDSARGS -v"
  440. fi
  441. PROGRESS_REPORTER=mysilentreporter
  442. if [ $VERBOSE -eq 1 ]; then
  443. PROGRESS_REPORTER=myreporter
  444. fi
  445. }
  446. setup_mailboxnames() {
  447. if [ -z "$MAILBOX" ]; then
  448. if [ -z "$MAILBOX_LOCAL" -o \
  449. -z "$MAILBOX_REMOTE" -o \
  450. -z "$TRANSLATOR_RL" -o \
  451. -z "$TRANSLATOR_LR" ]; then
  452. echo "The config file must define MAILBOX xor MAILBOX_LOCAL, MAILBOX_REMOTE, TRANSLATOR_LR and TRANSLATOR_RL"
  453. exit 1
  454. fi
  455. else
  456. if [ ! -z "$MAILBOX_LOCAL" -o ! -z "$MAILBOX_REMOTE" ]; then
  457. echo "The config file must define MAILBOX xor MAILBOX_LOCAL, MAILBOX_REMOTE, TRANSLATOR_LR and TRANSLATOR_RL"
  458. exit 1
  459. fi
  460. MAILBOX_LOCAL="$MAILBOX"
  461. MAILBOX_REMOTE="$MAILBOX"
  462. fi
  463. if echo "$MAILBOX_LOCAL $MAILBOX_REMOTE" | grep -q -e '\.\.'; then
  464. echo "Mailbox names can't contain .."
  465. exit 1
  466. fi
  467. resolve_translator "$TRANSLATOR_RL"
  468. TRANSLATOR_RL="$RC"
  469. resolve_translator "$TRANSLATOR_LR"
  470. TRANSLATOR_LR="$RC"
  471. }
  472. # this could be a system wide post-* hook
  473. report() {
  474. local exitcode="$1"
  475. local showtags="$2"
  476. local currcmd="$3"
  477. local inversecmd="$4"
  478. local localprog="$5"
  479. local remoteprog="$6"
  480. if [ $VERBOSE -eq 1 ]; then
  481. grep ^INFO: $SL | $SED 's/^INFO: //'
  482. grep ^INFO: $CL | $SED 's/^INFO: //'
  483. fi
  484. if [ $exitcode = 1 ]; then
  485. grep ^ERROR $SL \
  486. | $SED "s/^/$remoteprog: /" \
  487. | $SED "s/@@INVERSECOMMAND@@/$inversecmd/" \
  488. | $SED "s/@@ENDPOINT@@/$REPNAME/"
  489. grep ^ERROR $CL \
  490. | $SED "s/^/$localprog: /" \
  491. | $SED "s/@@INVERSECOMMAND@@/$inversecmd/" \
  492. | $SED "s/@@ENDPOINT@@/$REPNAME/"
  493. grep ^ssh: $SL \
  494. | $SED "s/^/$remoteprog: ERROR: /"
  495. fi
  496. if [ $showtags = 1 ]; then
  497. #echo "`date`: $currcmd $SERVERNAME" >> $CL
  498. grep ^TAGS $SL \
  499. | $SED "s/^/$REPNAME: $remoteprog@$SERVERNAME: /" \
  500. | $SED "s/@@INVERSECOMMAND@@/$inversecmd/" \
  501. | $SED "s/@@ENDPOINT@@/$REPNAME/"
  502. grep ^TAGS $CL \
  503. | $SED "s/^/$REPNAME: $localprog@localhost: /" \
  504. | $SED "s/@@INVERSECOMMAND@@/$inversecmd/" \
  505. | $SED "s/@@ENDPOINT@@/$REPNAME/"
  506. if [ `grep ^TAGS $SL|wc -l` = 0 ] && \
  507. [ `grep ^TAGS $CL|wc -l` = 0 ]; then
  508. # it may be that ssh failed to resolve the hostname
  509. # so we generate a fake tag for it
  510. cat $SL $CL
  511. echo "$REPNAME: $remoteprog@$SERVERNAME: TAGS: error::context(ssh) probable-cause(network) human-intervention(avoidable) suggested-actions(retry)"
  512. fi
  513. fi
  514. }
  515. ### Hooks ###
  516. run_hooks() {
  517. local dir="$1"
  518. local when="$2"
  519. local what="$3"
  520. local status="$4"
  521. for h in $dir/hooks/$when-$what.d/*; do
  522. if [ -x $h ]; then
  523. $h $when $what $REPNAME $status >> $CL 2>&1
  524. fi
  525. done
  526. }
  527. # running server and client with appropriate parameters
  528. run_local_client() {
  529. cd $WORKAREA; $SMDCLIENT $CHILDSARGS $SMDCLIENTOPTS -t "$TRANSLATOR_RL" $CLIENTNAME $MAILBOX_REMOTE
  530. }
  531. run_local_server() {
  532. cd $WORKAREA; $SMDSERVER $LOCALEXCLUDE $CHILDSARGS $SMDSERVEROPTS $CLIENTNAME $MAILBOX_REMOTE
  533. }
  534. run_remote_server() {
  535. $SSH $SERVERNAME $REMOTESMDSERVER $REMOTEEXCLUDE $CHILDSARGS $SMDSERVEROPTS $CLIENTNAME $MAILBOX_REMOTE
  536. }
  537. run_remote_client() {
  538. $SSH $SERVERNAME $REMOTESMDCLIENT $CHILDSARGS $SMDCLIENTOPTS $CLIENTNAME $MAILBOX_REMOTE
  539. }
  540. # vim:ts=4 filetype=sh: