Created
December 3, 2014 07:11
-
-
Save acidprime/12a5cf9e96dca255b7a5 to your computer and use it in GitHub Desktop.
My old Mail.app configuration script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
################################################################################# | |
# Mail Configuration Script Tiger Ed. v10.4.X version 0.139 Updated 11/12/06 # | |
################################################################################# | |
# # | |
# #### # | |
# #### papers (a) wallcity.org # | |
# #### #### # | |
# #### #### papers.wallcity.org # | |
# #### #### #### # | |
# #### #### #### Zachary Smith # | |
# #### #### #### # | |
# #### #### #### ACTC,ACSA,ACN,ACT # | |
# # | |
################################################################################# | |
# CVS: $Header$ # | |
################################################################################# | |
# HEADER # | |
################################################################################# | |
# shopt -s -o nounset | |
# Check for unset variables in script | |
# shopt -s -o monitor | |
# enable job control in script? | |
# Print usage. | |
USAGE() { | |
printf "%s\n\t" "USAGE:" | |
printf "%s\n\t" " ALL MAIL SERVERS:" | |
printf "%s\n\t" " -n | -new <type> ## inject config for server of type IMAP POP or EXG" | |
printf "%s\n\t" " -i | -incoming <servername>:<port> ## Port is optional,defaults to standard for connection and encryption." | |
printf "%s\n\t" " -o | -outoing <servername>:<port> ## Port is optional,defaults to standard for connection and encryption." | |
printf "%s\n\t" " -s | -same <servername> ## Use same server for in/out port defaults to standard for connection and encryption." | |
printf "%s\n\t" | |
printf "%s\n\t" " OPTIONAL FOR EXCHANGE SERVER:" | |
printf "%s\n\t" " -u | -url \"http://<servername>:<port>/exchange/\" ## configure OWA server defaults to <servername>/exchange" | |
printf "%s\n\t" | |
printf "%s\n\t" " ALL SERVERS:" | |
printf "%s\n\t" " -e | -encryption ## Use SSL encryption for Mail Host" | |
printf "%s\n\t" " -E | -encryptall ## Use SSL encryption for Mail and LDAP" | |
printf "%s\n\t" " -a | -authentication <type> PASS MD5 KRB4 NTLM KRB5" | |
printf "%s\n\t" " -p | -path </path/to/Users/> ## Path to homedirectory location, use \"CONSOLE\" for console user." | |
printf "%s\n\t" | |
printf "%s\n\t" " LDAP SERVER:" | |
printf "%s\n\t" " -l | ldap <servername>:<port> ## Port is optional,defaults to standard for connection and encryption." | |
printf "%s\n\t" " -L | -ldapurl configure ldap server: \"<ldaps://><servername>:<port>/<searchbase>/\" ## Must be in correct format." | |
printf "%s\n\t" | |
printf "%s\n\t" " OTHER TASKS:" | |
printf "%s\n\t" " -t | -template </path/to/save> ## Save configuration to a template" | |
printf "%s\n\t" " -c | -createpkg </path/to/newinstaller.pkg> ## Create a mail config package installer ( Dev Tools Must Be installed )" | |
printf "%s\n\t" " -f | -file </path/to/mailconfig.conf> ## Read configuration from a file." | |
printf "%s\n\t" " -m | -manual ## Configure script manually with an option to save config file." | |
printf "%s\n\t" " -h | -help ## Print this usage message and quit." | |
printf "%s\n\t" " -d | -directory </Active Directory/All Domains/> ## /LDAPv3/127.0.0.1/" | |
printf "%s\n\t" " -r | -remotedirectory ##" | |
printf "%s\n\t" | |
printf "%s\n\t" " EXAMPLE TASKS:" | |
printf "%s\n\t" " sudo $0 -n IMAP -i mail.mycompany.com -o smtp.mycompany.com -a MD5 -e -p /Users/" | |
printf "%s\n\t" " sudo $0 -u \"https://winmail.mycompany.com:443/exchange/\" -a NTLM -p /Users/" | |
printf "%s\n\t" " sudo $0 -L \"ldaps://ldap.mycompany.com:636/dc=mycompany,dc=com\" -a NTLM -p /Users/" | |
printf "%s\n\t" " sudo $0 -n IMAP -i mail.mycompany.com -o smtp.mycompany.com -a MD5 -e -p /Users/ -c /path/to/saved.pkg" | |
printf "%s\n" | |
} # END USAGE | |
# DIE function. | |
DIE(){ | |
declare LASTEXIT="$2" | |
CLEAN_UP || printf "%s\n" "ERROR: Unknown ERROR cleaning up" | |
USAGE >&2 # Print Usage. | |
printf "%s\n\v" "" "$1" >&2 # Print specifific error message for respective issue to standard error. | |
exit "${LASTEXIT:="192"}" # Exit with last status or 192 if non. | |
return 0 | |
} # END DIE | |
CLEAN_UP () { | |
# Clean up of our variables | |
unset ${!REQ*} | |
unset ${!EXG*} | |
unset ${!MAIL*} | |
unset ${!LDAP*} | |
unset ${!INPUT*} | |
# -- Clean up our Functions | |
unset -f INJECT_LAUNCHD | |
unset -f DIE | |
return 0 | |
printf "$SCRIPT ran in $SECONDS seconds" | |
} # END CLEAN_UP | |
# Run manual Interactive configurtion. | |
RUN_MANUAL() { | |
# First we must determine what type of Mail Server we are configuring. | |
printf "Starting Manual Configuration mode please enter <varibles> or hit return for [default]\n" | |
read -p "Please enter in the mail server's type <EXG> ,<POP>, or [IMAP]:" INPUT_MAILTYPE | |
QUESTIONS_ALL() { | |
read -p "Please enter in the incoming mail server's hostname [${INPUT_MAILHOST:-"mail.example.com"}] :" INPUT_MAILHOST | |
read -p "Please select the mail authentication type [${INPUT_MAILAUTH:-"PASSWORD"}]:" INPUT_MAILAUTH | |
read -p "Connect to server using SSL/TLS [YES]:" | |
read -p "Please enter in the incoming mail server's port [${GUESS_MAILPORT}] :" INPUT_MAILPORT | |
printf "%s\n" "Mail server's port set to:${INPUT_MAILPORT:=$GUESS_MAILPORT}" # If user hits return we use $GUESS_MAILPORT | |
} # END QUESTIONS_ALL | |
QUESTIONS_SMTP() { | |
read -p "Please enter in the outgoing mail server's hostname [${INPUT_SMTPHOST:-"smtp.exmple.com"}]:\n" INPUT_SMTPHOST | |
read -pn 6 "Please enter in the smtpoing mail server's port [${GUESS_MAILPORT}] :\n" INPUT_SMTPPORT | |
declare -i GUESS_SMTPPORT="25" | |
} # END QUESTIONS_SMTP | |
case $INPUT_MAILTYPE in | |
EXG | exg ) declare -x GUESS_MAILPORT="80" ; QUESTIONS_ALL || DIE "ERROR:$FUNCNAME: Unknown ERROR setting asking for input: EXG." 192 ;; | |
IMAP | imap ) declare -x GUESS_MAILPORT="143" ; QUESTIONS_ALL || DIE "ERROR:$FUNCNAME: Unknown ERROR setting asking for input: IMAP." 192 ;; | |
POP | pop ) declare -x GUESS_MAILPORT="110" ; QUESTIONS_ALL || DIE "ERROR:$FUNCNAME: Unknown ERROR setting asking for input: POP." 192 ;; | |
*) declare -x GUESS_MAILPORT="143" ; QUESTIONS_ALL || DIE "ERROR:$FUNCNAME: Unknown ERROR setting asking for input: IMAP." 192 ;; | |
esac | |
return 0 | |
} # END RUN_MANUAL | |
CREATE_CONFIG(){ | |
read -p "Where would you like to save the configuration file [${RUNDIRECTORY}/mailconfig.conf]:\n" SAVELOCATION | |
for CONFIGS in ${!INPUT*}; do # Glob and Grab all the varibles specified | |
echo "echo declare -x $CONFIGS=""\"\$${CONFIGS}\" | $sed 's/=/=\"/' | $sed 's/$/\"/g'>${SAVELOCATION:=$RUNDIRECTORY}/mailconfig.conf" >"${SAVELOCATION:=$RUNDIRECTORY}/mailconfig_unint.conf" # export varibles to source file | |
source "${SAVELOCATION:=$RUNDIRECTORY}/mailconfig_unint.conf" # Source the file and initialize the variables | |
done | |
printf "%s\n" "date +DATE: %m/%d/%y%nTIME: %H:%M:%S" > ${SAVELOCATION:=$RUNDIRECTORY}/mailconfig.conf | |
unset SAVELOCATION | |
} # END CREATE_CONFIG | |
# Set type | |
SET_MAILTYPE(){ | |
case "$1" in # Pass the run-time postional parameter to the function. | |
# -n <type> ## configure new mail server of type IMAP POP EXG | |
IMAP | imap ) declare -x INPUT_MAILTYPE="IMAPAccount" CONFIG_MAIL="YES" ;; | |
POP | pop ) declare -x INPUT_MAILTYPE="POPAccount" CONFIG_MAIL="YES" ;; | |
EXG | owa ) declare -x INPUT_MAILTYPE="ExchangeAccount" CONFIG_EXG="YES" ;; # Need check for template as it doesnt officially support exchange. | |
* ) DIE "ERROR:$FUNCNAME: Unknown option for new mail server type: $1" 192 ;; # Die clause for unknown options. | |
esac | |
return 0 | |
} # END SET_MAILTYPE | |
SET_AUTHTYPE() { | |
case "$1" in # Pass the run-time postional parameter to the function | |
PASS | pass ) declare -x INPUT_MAILAUTH="Password" ;; # Set the Password to type to Password | |
NTLM | ntlm ) declare -x INPUT_MAILAUTH="NTLM";; # Set the Password type to NT Lan Manager | |
MD5 | md5 ) declare -x INPUT_MAILAUTH="CRAM-MD5";; # Set the Password to CRAM-MD5 Challage Response | |
KRB4 | krb4 ) declare -x INPUT_MAILAUTH="KERBEROS_V4";; # Set The Password type Keberbos v4 | |
KRB5 | krb5 ) declare -x INPUT_MAILAUTH="GSSAPI";; # Set the Password type to Kerberos v5 (GSSAPI) | |
*) DIE "ERROR:$FUNCNAME: Unknown option for mail authentication: $1" 192 ;; # Die clause for unknown options. | |
esac | |
return 0 | |
} # END SET_AUTHTYPE | |
SET_SCOPE(){ | |
case "$1" in # Pass the run-time postional parameter to the function. | |
BASE | base ) declare -x INPUT_LDAPSCOPE="1" ;; | |
ONE | one ) declare -x INPUT_LDAPSCOPE="2" ;; | |
SUB | sub ) declare -x INPUT_LDAPSCOPE="3" ;; | |
*) DIE "ERROR:$FUNCNAME:$LINENO Unknown option for LDAP scope: $1" 192 ;; # Die clause for unknown options. | |
esac | |
return 0 # All is well | |
} # END SET_SCOPE | |
# Set home path for injection of LDAP,MAIL or FOO | |
SET_HOMEPATH(){ | |
case "$1" in | |
LOCAL | local ) HOMEPATH="/Users";; | |
NETWORK | local ) HOMEPATH;; | |
* ) declare -x HOMEPATH="$1";; | |
esac | |
} # END SET_HOMEPATH | |
SET_TEMPLATE_PATH(){ | |
case "$1" in | |
CONSOLE | console ) declare -x TEMPLATEPATH="${HOMPATH}/${CONSOLEUSER:?There does does not seem to be a console user!}/Library/Mail/AccountTypes/${MAILIDFR}/MailAccounts.plist";; | |
LOCAL | local ) declare -x TEMPLATEPATH="${DSTROOT}Library/Mail/AccountTypes/${MAILIDFR}/MailAccounts.plist";; | |
* ) declare -x TEMPLATEPATH="${1}${MAILIDFR}/MailAccounts.plist";; | |
esac | |
return 0 # All is well | |
} # END SET_TEMPLATE_PATH | |
PARSE_EXGURL(){ | |
URL_PREFIXHOSTPORT="${1%\/*}" | |
URL_PREFIX="${1%\/\/*}" | |
URL_PORT="${URL_PREFIXHOSTPORT#*:*:}" | |
URL_PREFIXHOST="${URL_PREFIXHOSTPORT%:*}" | |
URL_HOST="${URL_PREFIXHOST#http*:\/\/}" | |
return 0 # All is well | |
} # END PARSE_EXGURL | |
PARSE_LDAPURL(){ | |
URL_PREFIXHOSTPORT="${1%\/*}" | |
URL_PREFIX="${1%\/\/*}" | |
URL_PORT="${URL_PREFIXHOSTPORT#*:*:}" | |
URL_PREFIXHOST="${URL_PREFIXHOSTPORT%:*}" | |
URL_HOST="${URL_PREFIXHOST#ldap*:\/\/}" | |
URL_SEARCHBASE="${1#ldap*:*\/\/*/}" | |
if [ "$URL_PREFIX" = "ldaps:" ] ; then | |
declare -x INPUT_LDAPSSL="true" | |
elif [ "$URL_PREFIX" = "ldap:" ] ; then | |
declare -x INPUT_LDAPSSL="false" | |
fi | |
declare -x INPUT_LDAPHOST="$(${OPTARG})" | |
declare -x INPUT_LDAPBASE="${OPTARG#ldap*:*\/\/*/}" | |
return 0 # All is well | |
} # END PARSE_LDAPURL | |
# Standard Bash Check | |
[ ! -z "$BASH" ] || DIE "ERROR: Please run this script with the bash shell" 192 | |
# Check to see if script is running as root. | |
[ $EUID = 0 ] || DIE "ERROR: This script requires root privileges, you are user: $(/usr/bin/whoami)" 192 | |
if [ "$SCRIPT_NAME" != "postflight" ] ; then # PACKAGE INSTALLER TEST | |
# Check to see if we are running as a postflight script,the installer creates the $SCRIPT_NAME variable | |
while [[ $1 = -* ]]; do # Grab all the Options ( postial paramaeters ) no getopts for lots of reasons. | |
case "$1" in | |
# -- EXCHANGE SERVER (OPTIONAL) | |
-n | -new ) shift; SET_MAILTYPE "$1" declare -x CONFIG_MAIL="YES" || DIE "ERROR:$SCRIPT:SET_MAILTYPE:$LINENO ERROR setting mail type." 192 ;; # Run Function for mailtype | |
-u | -url ) shift; declare -x CONFIG_EXG="YES"; PARSE_EXGURL "$1" || DIE "ERROR:$SCRIPT:PARSE_EXGURL:$LINENO Unknown ERROR setting parsing exchange URL" 192 ;; # As a time saver you can specify the OWA Url "http://exchange.mycompany.com/exchange/" | |
# -- ALL MAIL SERVERS options for all mail servers. | |
-p | -path ) shift; declare -x HOMEPATH="$1" # -p | |
[ -z "$HOMEPATH" ] || [[ "$HOMEPATH" = -* ]] && DIE "ERROR: You must specify a path to home directories for injection." 192 ;; | |
-i | -incoming ) shift; declare -x INPUT_MAILHOST="$1" # -i <server hostname>:<port> ## Incoming mail server specification. | |
[ -z "$INPUT_MAILHOST" ] || [[ "$INPUT_MAILHOST" = -* ]] && DIE "ERROR: Incoming mail host not specified." 192 | |
[ $INPUT_MAILHOST = "${INPUT_MAILHOST#*:}" ] || declare -x INPUT_MAILPORT="${INPUT_MAILHOST#*:}";; # Extract port from argument. | |
-o | -outgoing ) shift; declare -x INPUT_SMTPHOST="$1" CONFIG_SMTP="YES" # -o <server hostname>:<port> ## Outgoing | |
[ -z "$INPUT_MAILHOST" ] || [[ "$INPUT_MAILHOST" = -* ]] && DIE "ERROR: Outgoing mail host not specified." 192 | |
[ $INPUT_SMTPHOST = "${INPUT_SMTPHOST#*:}" ] || declare -x INPUT_SMTPPORT="${INPUT_SMTPHOST#*:}";; # Extract port from argument. | |
-s | -same ) shift; declare -x INPUT_SMTPHOST="${1%:*}" INPUT_MAILHOST="${1%:*}" | |
[ -z "$INPUT_MAILHOST" ] || [[ "$INPUT_MAILHOST" = -* ]] && DIE "ERROR: Outgoing mail host not specified." 192 ;;# Leaving off ports of entered as they are different services. | |
-a | -authentication ) shift; MAILAUTH "$1" || DIE "ERROR:$SCRIPT:MAILAUTH:$LINENO Unknown ERROR setting authentication type" 192# -a <type> PASS MD5 NTLM KRB4 KRB5 | |
[ -z "$MAILAUTH" ] || [[ "$MAILAUTH" = -* ]] && DIE "ERROR: Mail authentication method not specified." 192 ;; | |
-e | -encrypt ) declare -x INPUT_MAILSSL="true" ;; # -e KERBEROS_V4 CRAM-MD5 NTLM GSSAPI | |
-E | -encyptall ) shift; declare -x INPUT_MAILSSL="true" INPUT_LDAPSSL="true" INPUT_EXGSSL="true" INPUT_EXGPORT="443" INPUT_IMAPPORT="993" INPUT_POPPORT="995" ;; | |
# -- LDAP SWITCHES: | |
-l | -ldap ) shift; declare -x INPUT_LDAPHOST="$1" CONFIG_LDAP="YES" | |
[ -z "$INPUT_LDAPHOST" ] || [[ "$INPUT_LDAPHOST" = -* ]] && DIE "ERROR: LDAP host not specified." 192 ;; | |
-L | -ldapurl ) shift; PARSE_LDAPURL "$1" || DIE "ERROR:$SCRIPT:PARSE_LDAPUR:$LINENO Unknown ERROR parsing LDAP URL" 192 ;; | |
-s | -scope ) shift; SET_SCOPE "$1" ;; # -scope <type> BASE ONE SUB | |
-b | -base ) shift; declare -x INPUT_LDAPBASE="$1" # -b | -base search base | |
[ -z "$INPUT_LDAPBASE" ] || [[ "$INPUT_LDAPBASE" = -* ]] && DIE "ERROR: LDAP search base not specified." 192 ;; | |
# -- OTHER TASKS: | |
-m | -manual )shift; RUN_MANUAL "$1" || DIE "ERROR:RUN_MANUAL: Unknown ERROR running manual configuration." 192 ;; # Run interactive "Manual" setup using read statements | |
-c | -createpkg ) declare -x INPUT_PKGLOC="$1" || DIE "ERROR: Package path must end with .pkg i.e. /Users/Shared/mailconfig.pkg" ;; | |
-t | -template ) INSTALL_TEMPLATE || DIE "ERROR:$SCRIPT:PARSE_LDAPUR:$LINENO Unknown ERROR installing template.";; | |
-h | -help ) USAGE; CLEAN_UP; exit 1 ;; | |
-z ) DIE "INFO: This script brought to you by Zack Smith email: zack (a) wallcity.org" ;; | |
*) DIE "ERROR: ${SCRIPT} : Unimplemented option specified \"$1\"" ;; | |
esac | |
done | |
elif | |
[ $# = 0 ] && USAGE >&2 && exit 1 # If we are not running postflight and no parameters given, print usage to stderr and exit status 1 | |
else | |
printf "%s\n" "Running script in postflight package mode." | |
delcare -x PKGBUNDLE="${1}" # Full path to the install package. | |
declare -x DSTROOT="${3}" # Installation Volme of mount point. | |
declare -x SYSROOT="${4}" # The root directory for the system. | |
fi # END PACKAGE INSTALLER TEST | |
# -- Required Folders | |
CHECK_FOLDERS() { | |
if [ -f "${REQFLD}" ] ; then | |
DIE "ERROR:$FUNCNAME: The required folder ${REQFLD} is not found." 192 | |
elif [ -w "${REQFLD}" ] ; then | |
DIE "ERROR:$FUNCNAME: The required folder ${REQFLD} is not writeable by user $($whoami)" 192 | |
else | |
declare -x READYTOGO="yes" | |
fi | |
} | |
########################################################## | |
# GLOBAL DECLARATIONS # | |
########################################################## | |
CHECK_CONFIGFILE() { | |
if [ ! -f "${SETTINGS:=$RUNDIRECTORY/mailconfig.conf}" ] ; then | |
printf "%s\n" "$SCRIPT: the file $CONFIGFILE is not available" >&2 | |
else | |
source "$CONFIGFILE" || DIE "ERROR: unable to parse config file: $CONFIGFILE, possibly does not have \"return 0\" on the last line." | |
fi | |
return 0 | |
} | |
# -- Envoirmental settings | |
declare -x SCRIPTPATH="${0}" | |
declare -x SCRIPT="${0##*/}" | |
declare -x RUNDIRECTORY="${0%%/*}" | |
declare -x SYSROOT="/" DSTROOT="/" | |
# -- Required Executables | |
declare -rx awk="/usr/bin/awk" | |
declare -rx cp="/bin/cp" | |
declare -rx chown="/usr/sbin/chown" | |
declare -rx date="/bin/date" | |
declare -rx defaults="/usr/bin/defaults" | |
declare -rx uuidgen="/usr/bin/uuidgen" | |
declare -rx grep="/usr/bin/grep" | |
declare -rx ldapsearch="/usr/bin/ldapsearch" | |
declare -rx ls="/bin/ls" | |
declare -rx openssl="/usr/bin/openssl" | |
declare -rx mkdir="/bin/mkdir" | |
declare -rx mv="/bin/mv" | |
declare -rx sed="/usr/bin/sed" | |
declare -x REQCMDS="$awk $cp $chown $date $defaults $uuidgen $grep $ldapsearch $ls $openssl $perl $mv $sed $who" # $packagemaker caught in CREATE_PKG | |
# -- Optional Executables | |
declare -x packagemaker="/Developer/Applications/Utilities/PackageMaker.app/Contents/MacOS/PackageMaker" | |
declare -x OSFLAVOR="CLIENT" ; [ ! -f /System/Library/CoreServices/ServerVersion.plist ] || declare -x OSFLAVOR="SERVER" # Check for client or server. | |
declare -x OSVER="`$defaults read "${SYSROOT}System/Library/CoreServices/SystemVersion" ProductVersion `" | |
declare -x CONFIGFILE="${RUNDIRECTORY:=/tmp}/mailconfig.conf" | |
declare -x UTCDATE=$($date -u "+%Y-%m-%dT%H:%M:%SZ") | |
declare -x UUIDGEN=$($uuidgen) | |
declare -x SCRIPTLOG="${DSTROOT}Library/Preferences/mailconfig.log" | |
# -- LDAP Servers | |
if [ "$CONFIG_LDAP" = "YES" ] ; then | |
declare -r LDAPUUID="$($uuidgen)" | |
declare -x LDAPHOST="${INPUT_LDAPHOST:?"ERROR:The LDAP server must be defined."}" | |
declare -x LDAPSSL="${INPUT_LDAPSSL:="false"}" | |
declare -x LDAPPORT="${INPUT_LDAPHOST:="389"}" | |
declare -x LDAPBASE="${INPUT_LDAPBASE%\./,dc=}" | |
declare -x LDAPSCOPE="${INPUT_LDAPSCOPE:=2}" | |
# -- Active Directory LDAP | |
declare -x ADLDAPHOST="$LDAPHOST" | |
declare -x ADLDAPPORT="$LDAPPORT" | |
declare -x ADLDAPBASE="$LDAPBASE" | |
# -- Open Directory LDAP | |
declare -x ODLDAPHOST="$LDAPHOST" | |
declare -x ODLDAPPORT="$LDAPPORT" | |
declare -x ODLDAPBASE="$LDAPBASE" | |
declare -x EXCLUDEDUSERS="$INPUT_EXUSERS" | |
fi | |
# -- All Mail Servers. | |
[ "$CONFIG_IMAP" = "YES" ] && declare -x MAILSRVPORT="${INPUT_IMAPPORT:=143}" # Defaults to standard IMAP 143 unless encryption is turned on. | |
[ "$CONFIG_POP" = "YES" ] && declare -x MAILSRVPORT="${INPUT_POPPORT:=110}" # Defaults to standard POP 110 unless encryption is turned on. | |
[ "$CONFIG_EXG" = "YES" ] && declare -x MAILSRVPORT="${INPUT_EXGPORT:=80}" # Defaults to standard OWA 80 unless encryption is turned on. | |
# -- IMAP and POP Servers | |
if [ "$CONFIG_MAIL" = "YES" ] ; then | |
declare -x MAILTYPE="${INPUT_MAILTYPE:?"ERROR:The mail type <EXG> <IMAP> <POP> must be defined."}" | |
declare -x MAILHOST="${INPUT_MAILHOST:?"ERROR:The mail host must be defined."}" | |
declare -x MAILNAME="${INPUT_MAILNAME:=INPUT_MAILHOST}" | |
declare -x MAILDOMAIN="${INPUT_MAILDOMAIN}" | |
declare -x MAILIDFR="$(echo $INPUT_MAILHOST | $awk -F . '{print $3"."$2"."$1}' | $sed 's/^[.]//g')" # Change mail.example.com to com.example.mail | |
declare -x MAILAUTH="${INPUT_MAILAUTH:?"ERROR:The mail authentication method must be defined."}" # Catch for required varible | |
declare -x MAILSSL="${INPUT_MAILSSL:=false}" # Defalts to false unless specified by the user. | |
declare -x MAILPORT="${INPUT_MAILPORT:=$MAILSRVPORT}" # Defaults to standard/encrypted unless user specified one. | |
fi | |
# -- Exchange Servers | |
if [ "$CONFIG_EXG" = "YES" ] ; then | |
declare -x EXGTYPE="$INPUT_EXGTYPE" | |
declare -x EXGHOST="${INPUT_EXGHOST:?"ERROR: The exchange host must be specified."}" # Catch for required varible | |
declare -x EXGURL="${EXGHOST/$EXGHOST/http\:\/\/$EXGHOST\/exchange}" # Changes the mail host into a http URL | |
declare -x EXGSURL="${EXGHOST/$EXGHOST/https\:\/\/$EXGHOST\/exchange}" # Changes the mail host into a https URL | |
declare -x EXGNAME="${INPUT_EXGNAME:=$INPUT_EXGHOST}" # If no name specified defaults to hostname of server. | |
declare -x EXGSSL="${INPUT_EXGSSL:="false"}" | |
declare -x EXGPUBFLDR="$INPUT_EXGPUBFLDR" | |
declare -x EXGURL="$INPUT_EXGURL" | |
fi | |
# -- SMTP Servers | |
if [ "$CONFIG_SMTP" = "YES" ] ; then | |
declare -x SMTPHOST="${INPUT_SMTPHOST:?"ERROR:The smtpoing server address must be specified."}" # Catch for required varible | |
declare -x SMTPAUTH="${INPUT_SMTPAUTH:=none}" # Defalts to none unless specified by the user. | |
declare -x SMTPNAME="${INPUT_SMTPNAME:="INPUT_SMTPHOST"}" # If no name specified defaults to hostname of server. | |
declare -x SMTPSSL="${INPUT_SMTPSSL:="false"}" # Defalts to false unless specified by the user. | |
declare -x SMTPPORT="${INPUT_SMTPPORT:="25"}" # Defaults to 25 unless specified by the user. | |
declare -x STMPUSEAUTH="${INPUT_SMTPUSEA:=YES}" # Defalts to YES unless specified by the user. | |
fi | |
########################################################## | |
# SANITY CHECKS # | |
########################################################## | |
# -- Required Commands installed check for every piece of software needed | |
CHECK_CMDS(){ | |
for RQCMD in "$REQCMDS" ; do | |
if [ ! -x "$RQCMD" ] ; then | |
DIE "ERROR:$SCRIPT: the command $RQCMD is not available Ñ aborting" 192 >&2 | |
fi | |
done | |
} # END CHECK_CMDS | |
CHECK_OS() { | |
case $OSVER in | |
10.0* | 10.1* | 10.2* | 10.3*) DIE "$FUNCNAME: Unsupported OS version: $OSVER." 192 ;; | |
10.4*) return 0 ;; | |
10.5*) DIE "ERROR:$FUNCNAME:$LINENO Unsupported OS version : $OSVER is too new." 192;; | |
*) DIE "ERROR:$FUNCNAME:$LINENO Unsupported OS version : $OSVER unknown version." 192;; | |
esac | |
} # END CHECK_OS | |
######################################################## | |
# MAIN FUNCTIONS # | |
######################################################## | |
RUN(){ | |
CHECK_CMDS # Check for Require Commands | |
[ $CONFIG_MAIL != "YES" ] INJECT mail || DIE "ERROR: injecting incoming server config." 192 | |
[ $CONFIG_SMTP != "YES" ] INJECT smtp || DIE "ERROR: injecting smtpoing server config." 192 | |
[ $CONFIG_LDAP != "YES" ] INJECT ldap || DIE "ERROR: injecting LDAP config." 192 | |
[ $CONFIG_EXG != "YES" ] INJECT exg || DIE "ERROR: Unkown error injecting exchange config." 192 | |
} # END RUN | |
# Use Regex and postional parameters to verfiy input give to INPUT_* varibles | |
CHECK_USER_INPUT() { | |
} | |
# MAIN Inject Function for running respective injections. | |
INJECT(){ | |
# Set the plist identifier | |
case "$1" in | |
mail) declare PLISTID="com.apple.mail" PREFKEY="MailAccounts" CHKHOST="$MAILHOST" MAILUUID="$($uuidgen)";; | |
exg) declare PLISTID="com.apple.mail" PREFKEY="MailAccounts" CHKHOST="$EXGHOST" EXGUUID="$($uuidgen)";; | |
ldap) declare PLISTID="com.apple.AddressBook" PREFKEY="AB3LDAPServers" CHKHOST="$LDAPHOST" LDAPUUID="$($uuidgen)";; | |
smtp) declare PLISTID="com.apple.mail" PREFKEY="DeliveryAccounts" CHKHOST="$SMTPHOST" SMTPUUID="$($uuidgen)";; | |
esac | |
# Start the recursion through the home directories starting with the console user first. | |
for CURRENTHOMEDIR in "$CONSOLEHOME" "${HOMEPATH}/*"; do | |
# For all users who's home directories that are in the HOMEPATH do the following: | |
# Test first for File Vault images and short circuit as some installers incorrectly create a ~/Library folder in this place holder directory when the users not logged in. | |
# Test to make sure the Directory ~/Library/Preferences/ exists ,Pretty much here for "/Users/Shared" "/Users/Deleted Users". | |
if [ -d "${CURRENTHOMEDIR}/Library/Preferences" ] ; then # Catch for "Deleted Users" and File Vault | |
# temp varibles for this recursion. | |
declare SERVICENAME="$1" | |
declare CNME=$($ls -ld "${CURRENTHOMEDIR}/Library" | $awk '{print $3}') # Pull the username from the ~/Library's owner. | |
declare PLIST="${CURRENTHOMEDIR}/Library/Preferences/$PLISTID.plist" | |
declare PLISTBACKUP="${PLIST}.bkp" # This is the file that you need to restore if the sky falls out from under us and the script does do it. | |
declare ISCONFIGTHERE=$($defaults read "${PLIST%.plist}" "$PREFKEY" | $grep $CHKHOST) || DIE "There was an error reading file: ${PLIST%.plist}" | |
# Check to see an the address-book plist exists for the script's current user on the system | |
# Check for plist and then move on or fail to else | |
if [ -f "$PLIST" ] && [ -z "$ISCONFIGTHERE" ] ; then # Check to see an LDAP Entry already exists for ldap.company.com | |
[ -f "${CURRENTHOMEDIR}/$CNME.sparseimage" ] || break | |
$cp -p "$PLIST" "$PLISTBACKUP" || DIE "There was an error copying the file $PLIST to $PLISTBACKUP." 192 # Back up the old preferences up before we change anything( copies and preserves permissions and adds a .bkp extension | |
INJECT_LDAP_ADD "$PLIST" $CNME | |
CHECK_PLIST "$PLIST" "$PLISTBACKUP" "$CURRENTHOMEDIR" "$PLISTID" || break # Check the plist for errors. | |
elif [ ! -f "$PLIST" ] ; then | |
INJECT_LDAP_CLEAN "${CURRENTHOMEDIR}" | |
# Check .plist for syntax errors,seems like it almost always exit with 0 , but cant hurt. | |
CHECK_PLIST "$PLIST" "$PLISTBACKUP" "$CURRENTHOMEDIR" "$PLISTID" || break # Check the plist for errors. | |
# Status info for the Installer Log | |
printf "%s\n" "The $SERVICENAME entry for $CHKHOST seems to already exist for $CNME please manually delete if you want it to be added by this installer" | |
fi | |
fi | |
done | |
# all is well even if we skipped the pref's because ldap.company.com was already there,mainly so you can run the script multiple times. | |
return 0 | |
} # END INJECT | |
# Console function | |
CHECK_CONSOLE(){ | |
declare -x CONSOLEUSER=$($who | $grep console | $awk '{print $1}') | |
} | |
# -- Kill processes like Mail and Address Book if there is a console user logged in. | |
QUIT_APPS(){ | |
if [ -n $($who | $grep console | $awk '{print $1}') ] ; then | |
for APPS in "Mail.app" "Address Book.app"; do # This dont work yet | |
osascript <<EOF | |
try | |
tell application "System Events" | |
set IsMailRunning to count (every process whose name is "Mail.app") | |
if IsMailRunning is not equal to 0 then | |
tell application "Mail.app" | |
quit | |
end tell | |
end if | |
end tell | |
end try | |
EOF | |
done | |
fi | |
} # END CHECK_CONSOLE | |
# Check Active Directory users | |
CHECK_DIR_USER(){ | |
declare CNME="$1" | |
declare ADCOMPASS="$defaults read /Library/Preferences/DirectoryService/ActiveDirectory \"AD Computer Password\" | $openssl enc -base64 -d" | |
declare ADCOMPNAME="$defaults read /Library/Preferences/DirectoryService/ActiveDirectory \"AD Computer Password\"" | |
declare ADCOMPOU="$defaults read /Library/Preferences/DirectoryService/ActiveDirectory \"AD Computer Password\"" | |
$ldapsearch -h $ADLDAPHOST -x -D "cn=${ADCOMPNAME},$ADCOMPOU" -w "$ADCOMPASS" -b "$ADLDAPBASE" "cn=$CNME" | |
unset ADCOMPASS | |
$dscl "$DIRNODE" -search / RecordName "$CNME" | |
} # END CHECK_ADUSER | |
INJECT_LDAP_ADD() { | |
declare CURRENTHOMEDIR="$1" | |
declare CNME="$2" | |
$defaults write "${CURRENTHOMEDIR}/Library/Preferences/com.apple.AddressBook" "AB3LDAPServers" -array-add " | |
<dict> | |
<key>ServerInfo</key> | |
<dict> | |
<key>AuthenticationType</key> | |
<false/> | |
<key>Base</key> | |
<string>$LDAPBASE</string> | |
<key>Enabled</key> | |
<true/> | |
<key>HostName</key> | |
<string>$LDAPHOST</string> | |
<key>Port</key> | |
<integer>$LDAPPORT</integer> | |
<key>SSL</key> | |
<${LDAPSSL:-"false"}/> | |
<key>Scope</key> | |
<integer>2</integer> | |
<key>Title</key> | |
<string>$LDAPHOST</string> | |
<key>UID</key> | |
<string>$LDAPUUID</string> | |
<key>Username</key> | |
<string>$LDAPUSER</string> | |
</dict> | |
<key>ServerType</key> | |
<integer>0</integer> | |
</dict> | |
" | |
} # END INJECT_LDAP_ADD | |
# Generate a new preference file as it doesnt exist, with the default values added and an entry for out ldap server. | |
INJECT_LDAP_CLEAN() { | |
declare CURRENTHOMEDIR="$1" | |
declare CNME="$2" | |
printf "%s\n" "Writing new preference file with $LDAPHOST entry for $CNME in ${CURRENTHOMEDIR}/Library/Preferences/com.apple.AddressBook" | |
$defaults write "${CURRENTHOMEDIR}/Library/Preferences/com.apple.AddressBook" " | |
<dict> | |
<key>AB21vCardEncoding</key> | |
<string>MACINTOSH</string> | |
<key>AB3LDAPServers</key> | |
<array> | |
<dict> | |
<key>ServerInfo</key> | |
<dict> | |
<key>AuthenticationType</key> | |
<false/> | |
<key>Base</key> | |
<string>$LDAPBASE</string> | |
<key>Enabled</key> | |
<true/> | |
<key>HostName</key> | |
<string>$LDAPHOST</string> | |
<key>Port</key> | |
<integer>$LDAPPORT</integer> | |
<key>SSL</key> | |
<${LDAPSSL:="false"}/> | |
<key>Scope</key> | |
<integer>$LDAPSCOPE</integer> | |
<key>Title</key> | |
<string>$LDAPHOST</string> | |
<key>UID</key> | |
<string>$LDAPUUID</string> | |
<key>Username</key> | |
<string>${LDAPUSER:=}</string> | |
</dict> | |
<key>ServerType</key> | |
<integer>0</integer> | |
</dict> | |
</array> | |
<key>ABAIMInstantVisible</key> | |
<true/> | |
<key>ABAddressesVisible</key> | |
<true/> | |
<key>ABCardPaneFrame</key> | |
<string>{{260, 0}, {300, 207}}</string> | |
<key>ABDefaultAddressCountryCode</key> | |
<string>us</string> | |
<key>ABDefaultLayout</key> | |
<integer>0</integer> | |
<key>ABDefaultSelectedMember</key> | |
<string>$LDAPUUID:ABPerson</string> | |
<key>ABEmailsVisible</key> | |
<true/> | |
<key>ABGroupsPaneFrame</key> | |
<string>{{0, 0}, {120, 207}}</string> | |
<key>ABHomePageVisible</key> | |
<true/> | |
<key>ABImportTipCards</key> | |
<true/> | |
<key>ABIndexVersionKey</key> | |
<integer>2</integer> | |
<key>ABMembersPaneFrame</key> | |
<string>{{125, 0}, {130, 207}}</string> | |
<key>ABMetaDataChangeCount</key> | |
<integer>180</integer> | |
<key>ABNameDisplay</key> | |
<integer>0</integer> | |
<key>ABNameSorting</key> | |
<integer>1</integer> | |
<key>ABPeopleColumnsWidth</key> | |
<real>113</real> | |
<key>ABPhoneFormat-Edited</key> | |
<false/> | |
<key>ABPhoneFormat-Enabled</key> | |
<true/> | |
<key>ABPhoneFormat-PhoneFormatter</key> | |
<array> | |
<string>+1-###-###-####</string> | |
<string>1-###-###-####</string> | |
<string>###-###-####</string> | |
<string>###-####</string> | |
</array> | |
<key>ABPhonesVisible</key> | |
<true/> | |
<key>ABRelatedRecordsVisible</key> | |
<true/> | |
<key>ABSKCompactionHint</key> | |
<integer>3</integer> | |
<key>ABSeparateWindowsFrames</key> | |
<array/> | |
<key>ABSeparateWindowsHiddenUIDs</key> | |
<array/> | |
<key>ABSeparateWindowsUIDs</key> | |
<array/> | |
<key>ABTextSizeFixed</key> | |
<true/> | |
<key>NSPreferencesContentSize</key> | |
<string>{461, 414}</string> | |
<key>NSPreferencesSelectedIndex</key> | |
<integer>0</integer> | |
<key>NSWindow Frame Preferences</key> | |
<string>26 91 593 390 0 0 1024 746 </string> | |
</dict>" | |
return 0 | |
} # END INJECT_LDAP_CLEAN | |
CHECK_PLIST(){ | |
declare PLIST="$1" | |
declare PLISTBACKUP="$2" | |
declare CURRENTHOMEDIR="$3" | |
declare PLISTID="$4" | |
declare CGID=$($ls -lnd "${CURRENTHOMEDIR}/Library" | $awk '{print $4}') | |
declare CUID=$($ls -lnd "${CURRENTHOMEDIR}/Library" | $awk '{print $3}') | |
$chown "$CUID":"$CGID" "$PLIST" # As this script is running as root we need to change the POSIX permissions,I use numerics for the parent pref's folder. | |
if [ $($plutil -lint "$PLIST") ] ; then # Check .plist for syntax errors,seems like it almost always exits with 0 , but cant hurt. | |
return 0 | |
else | |
printf "%s\n" "WARNING: There was a problem editing plist: "${CURRENTHOMEDIR}"/Library/Preferences/${PLISTID}.plist" | |
printf "%s\n" "Reverting to copy: $PLISTBACKUP and continuing on." | |
$mv -f "$PLISTBACKUP" "$PLIST" # Replace old plist with orginal. | |
return 192 | |
fi | |
} # END CHECK_PLIST | |
# Inject incoming. | |
INJECT_INCOMING() { | |
# Dump the raw XML "dictionary" into a new array called | |
# This will be additive and should not destroy any data. | |
# and the forums said you cant add a dictionary to an array with defaults | |
declare CURRENTHOMEDIR="$1" | |
declare CNME="$2" | |
$defaults write "${CURRENTHOMEDIR}/Library/Preferences/com.apple.mail" "MailAccounts" -array-add " | |
<dict> | |
<key>AccountName</key> | |
<string>$MAILNAME</string> | |
<key>AccountPath</key> | |
<string>~/Library/Mail/IMAP-$CNME@$MAILHOST</string> | |
<key>AccountType</key> | |
<string>$MAILTYPE</string> | |
<key>AuthenticationScheme</key> | |
<string>$MAILAUTH</string> | |
<key>DateOfLastSync</key> | |
<date>$UTCDATE</date> | |
<key>DaysBetweenSyncs</key> | |
<integer>7</integer> | |
<key>DraftsMailboxName</key> | |
<string>Drafts</string> | |
<key>EmailAddresses</key> | |
<array> | |
<string>$CNME@$MAILDOMAIN</string> | |
</array> | |
<key>FullUserName</key> | |
<string>$CNME</string> | |
<key>Hostname</key> | |
<string>$MAILHOST</string> | |
<key>ISPAccountID</key> | |
<string>$UUIDGEN</string> | |
<key>SMTPIdentifier</key> | |
<string>$MAILHOST:$CNME</string> | |
<key>SentMessagesMailboxName</key> | |
<string>Sent Messages</string> | |
<key>StoreDraftsOnServer</key> | |
<string>YES</string> | |
<key>StoreSentMessagesOnServer</key> | |
<string>YES</string> | |
<key>TrashMailboxName</key> | |
<string>Deleted Messages</string> | |
<key>Username</key> | |
<string>$CNME</string> | |
<key>uniqueId</key> | |
<string>$MAILUUID</string> | |
</dict>" | |
mkdir -p $HOME/Library/Mail/IMAP-$CNME\@$MAILHOST/INBOX.imapmbox/ # Not sure I need this | |
$defaults write $CURRENTHOME/Library/Preferences/com.apple.mail "ReleaseNotesVersion" -int "3" # Or this | |
} # END INJECT_INCOMING | |
# Inject the SMTP server configuration. | |
INJECT_OUTGOING() { | |
declare CURRENTHOMEDIR="$1" | |
declare CNME="$2" | |
$defaults write ${CURRENTHOME}/Library/Preferences/com.apple.mail "DeliveryAccounts" -array-add " | |
<dict> | |
<key>AccountType</key> | |
<string>SMTPAccount</string> | |
<key>Hostname</key> | |
<string>$SMTPHOST</string> | |
<key>PortNumber</key> | |
<string>$SMTPPORT</string> | |
<key>SSLEnabled</key> | |
<string>$SMTPSSL</string> | |
<key>ShouldUseAuthentication</key> | |
<string>${SMTPUSEA:-YES}</string> | |
<key>Username</key> | |
<string>$CNME</string> | |
<key>uniqueId</key> | |
<string>$SMTPUUID</string> | |
</dict>" | |
return 0 | |
} # END INJECT_OUTGOING | |
# Install a Mail "Template" or what Apple calls a Mail Bundle | |
INSTALL_TEMPLATE() { | |
$defaults write "${TEMPLATEPATH}" -dict " | |
<key>AccountIconName</key> | |
<string>$MAILNAME</string> | |
<key>Accounts</key> | |
<array> | |
<dict> | |
<key>AccountID</key> | |
<string>$MAILUUID</string> | |
<key>AccountName</key> | |
<string>$MAILNAME</string> | |
<key>AuthenticationScheme</key> | |
<array> | |
<string>$MAILAUTH</string> | |
</array> | |
<key>AuthenticationSchemeIsEditable</key> | |
<false/> | |
<key>DeliveryAccounts</key> | |
<array> | |
<string>$($uuidgen)</string> | |
</array> | |
<key>EmailAddressDomain</key> | |
<string>@$MAILNAME</string> | |
<key>PortNumber</key> | |
<integer>$MAILPORT</integer> | |
<key>Protocol</key> | |
<string>$MAILTYPE</string> | |
<key>SSLEnabled</key> | |
<${MAILSSL:-false}/> | |
<key>SSLEnabledIsEditable</key> | |
<false/> | |
<key>ServerName</key> | |
<array> | |
<string>$MAILHOST</string> | |
</array> | |
<key>ServerNameIsEditable</key> | |
<false/> | |
<key>UserNameMatchesEmailAddress</key> | |
<true/> | |
</dict> | |
<dict> | |
<key>AccountID</key> | |
<string>$SMTPUUID</string> | |
<key>AccountName</key> | |
<string>$SMTPNAME</string> | |
<key>AuthenticationScheme</key> | |
<array> | |
<string>$SMTPAUTH</string> | |
</array> | |
<key>AuthenticationSchemeIsEditable</key> | |
<false/> | |
<key>PortNumber</key> | |
<integer>$SMTPPORT</integer> | |
<key>PortNumberIsEditable</key> | |
<false/> | |
<key>Protocol</key> | |
<string>SMTP</string> | |
<key>SSLEnabled</key> | |
<${SMTPSSL:-false}/> | |
<key>SSLEnabledIsEditable</key> | |
<false/> | |
<key>ServerName</key> | |
<string>$SMTPNAME</string> | |
<key>ServerNameIsEditable</key> | |
<false/> | |
</dict> | |
</array> | |
<key>Identifier</key> | |
<string>$MAILIDFR</string> | |
<key>Version</key> | |
<integer>1</integer>" | |
return 0 | |
} # END INSTALL_TEMPLATE | |
# Install LaunchD item for auto run of application? | |
INJECT_LANUCHD() { | |
declare LAUNCHJOB="$1" | |
declare WATCHFOLDER="$2" | |
$defaults write ${CURRENTHOMEDIR}/Library/LaunchDeamons/$MAILIDFR.notify " | |
<dict> | |
<key>Label</key> | |
<string>$MAILIDFR.notify</string> | |
<key>ProgramArguments</key> | |
<array> | |
<string>$LAUNCHJOB</string> | |
</array> | |
<key>QueueDirectories</key> | |
<array> | |
<string>$WATCHFOLDER</string> | |
</array> | |
<key>RunAtLoad</key> | |
<true/> | |
<key>WatchPaths</key> | |
<array> | |
<string>${CURRENTHOMEDIR}/Library/Mail</string> | |
</array> | |
</dict>" | |
return 0 | |
} # END INJECT_LANUCHD | |
EXPORT_CONFIG(){ | |
printf "%s\n" >"$CONFIGFILE" | |
return 0 # Return all is well. | |
} | |
# Create a package installer (.pkg) capable of pushing this mail configuration through Apple Remote Desktop. | |
CREATE_PKG() { | |
# "Sub" Functions for creating Package info.plist. | |
CREATE_PKG_INFO(){ | |
declare SESSIONTMP="$1" | |
defaults write "${SESSIONTMP}/Info" "<dict> | |
<key>CFBundleGetInfoString</key> | |
<string>0.1, ${MAILDOMAIN:="Mail Installer"}</string> | |
<key>CFBundleIdentifier</key> | |
<string>${MAILIDFR}.mailconfig</string> | |
<key>CFBundleShortVersionString</key> | |
<string>0.1</string> | |
<key>IFMajorVersion</key> | |
<integer>0</integer> | |
<key>IFMinorVersion</key> | |
<integer>1</integer> | |
<key>IFPkgFlagAllowBackRev</key> | |
<false/> | |
<key>IFPkgFlagAuthorizationAction</key> | |
<string>AdminAuthorization</string> | |
<key>IFPkgFlagBackgroundAlignment</key> | |
<string>topleft</string> | |
<key>IFPkgFlagBackgroundScaling</key> | |
<string>none</string> | |
<key>IFPkgFlagDefaultLocation</key> | |
<string>/</string> | |
<key>IFPkgFlagFollowLinks</key> | |
<true/> | |
<key>IFPkgFlagInstallFat</key> | |
<false/> | |
<key>IFPkgFlagInstalledSize</key> | |
<integer>900</integer> | |
<key>IFPkgFlagIsRequired</key> | |
<false/> | |
<key>IFPkgFlagOverwritePermissions</key> | |
<false/> | |
<key>IFPkgFlagRelocatable</key> | |
<false/> | |
<key>IFPkgFlagRestartAction</key> | |
<string>NoRestart</string> | |
<key>IFPkgFlagRootVolumeOnly</key> | |
<false/> | |
<key>IFPkgFlagUpdateInstalledLanguages</key> | |
<false/> | |
<key>IFPkgFormatVersion</key> | |
<real>0.10000000149011612</real> | |
</dict>" | |
return 0 | |
} # END CREATE_PKG_INFO | |
# Sub Function for creating package description. | |
CREATE_PKG_DISC(){ | |
declare SESSIONTMP="$1" | |
defaults write "${SESSIONTMP}/Description" " | |
<dict> | |
<key>IFPkgDescriptionDescription</key> | |
<string>Title | |
Line1 | |
Line2 | |
Line3</string> | |
<key>IFPkgDescriptionTitle</key> | |
<string>Mail Configuration Installer</string> | |
</dict>" | |
return 0 | |
} # END CREATE_PKG_DISC | |
# -- Package Installer and Mail Template. | |
declare PKGLOC="${INPUT_PKGLOC:=/Users/Shared/mailconfig.pkg}" | |
# Check to see if package maker is executable and where we think it is. | |
if [ ! -x "$packagemaker" ] ; then | |
DIE "Package Maker does not seem to be installed ; You must have to the Developer tools installed to use this feature. file: ${packagemaker}" | |
fi | |
# CREATE_PKG_DISC session variables. | |
declare SESSIONTMP="/private/tmp/${0##*/}_${$}_${EUID}" # Create temp directory for the session, ala /private/tmp/nameofscript_PID_EUID/ | |
declare PKGSCPTS="${SESSIONTMP:="/tmp"}/rsrcfiles" # Package resources, in this case the scripts and config files. | |
declare FAUXROOT="${SESSIONTMP:="/tmp"}/fauxroot" # The faux or "dstroot" | |
declare PKGINFO="${SESSIONTMP:="/tmp"}/Info.plist" # The packages info plist | |
declare PKGDISC="${SESSIONTMP:="/tmp"}/Description.plist" # The packages description plist. | |
printf "s\n" "Creating temp directory in $SESSTMP for package maker files." | |
for TEMPFOLDERS in "$SESSIONTMP" "$PKGSCPTS" "$FAUXROOT"; do | |
printf "%s\n" "Attempting to create temp directory ${TEMPFOLDERS}" | |
$mkdir "${TEMPFOLDERS}" || DIE "ERROR: The creating directory: $TEMPFOLDERS ." 192 | |
done | |
printf "%s\n" "Copying ${SCRIPTPATH} ${PKGSCPTS}/postflight." | |
$cp "${SCRIPTPATH}" "${PKGSCPTS}/postflight" # Move this script in to the postflight. | |
$cp "$CONFIGFILE" "$PKGSCPTS/" || DIE "ERROR: The config file: $CONFIGFILE was not found" 192 # Copy the current settings to the package scripts directory. | |
CREATE_PKG_INFO "$SESSIONTMP" # Create Info file in the session's temp directory. | |
CREATE_PKG_DISC "$SESSIONTMP" # Create Discription file in the session's temp directory. | |
$mkdir -p "${FAUXROOT}Library/Mail/AccountTypes/" && INSTALL_TEMPLATE "$FAUXROOT" # Create mail template or "bundle" file to be installed in root directory. | |
$packagemaker -build -p "$PKGLOC" -ds -f "$FAUXROOT" -r "$PKGSCPTS" -b "/private/tmp/" -i "$PKGINFO" -d "$PKGDISC" # use package maker to create package. | |
return 0 | |
} # END CREATE_PKG | |
################################################## | |
## CLEANUP ## | |
################################################## | |
trap CLEAN_UP SIGHUP SIGINT SIGTERM | |
unset -f CLEAN_UP |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Automatic Mail Configuration in Mail.app and Entourage
Introduction (Feel free to skip to setup)
Email account settings are one of those things that most end users have to deal with at some point in their career,some times its just to call IT to help the user setup a new account,or more often to have IT setup a new account for a new employee. Sometime its trouble shooting a connection over the phone due to a hotel SMTP restriction or just incorrect “external” settings leading to a “it worked at the office” problem. Either way while its a relatively small amount of information which in the case of email software (clients) you only have to enter in once, To the uninitiated its a smorgasbord board of acronyms and complex names they don’t care (nor should they need) to remember.
I hope to show you In this article that by leveraging built-in technologies like Apple Script,Installation packages and potentially Launchd or Login items you can allow your end users to enter/verify just their Account ID,Full Name and Reply to Address to complete setup for a new account. In fact using some semi-fancy piece's of code you can have defaults entered if for them,so they just have to change what they like for instance “Zach Smith” to “Zack Smith”, Meaning now your users can setup new email accounts by just pressing return and following the prompts. Apple’s Mail.app program provides help with this by using templates that you can create and that are tightly integrated into Mail as of v10.4 .In addition with supplied Apple Script’s that can be used as the basis for your own scripts you can make a automated application for setting up a new account. In writing this article I have also included some fairly complete scripts which you can use to start with just by changing the variables to suit your configuration.
Microsoft Entourage is a slightly more manual configuration as it does not support any documented account templates, currently like Mail.app it also supports a rich Apple Script layer which can allow you create scripts that with a careful placement can provide some basic “template” functionality. This article is divided in sections pertaining to the respective email software you are using and the intended deployment methodology .I have sectioned these off by Single user(s),All users on a local system and All users on s network system like (Active | Open) Directory. One last note,the following PDF is link-alicious many items have file system links that will open up folders,applications and even scripts in your console,I have tried to make these links as non-destructive as possible, however I would recommend verifying your path names and intended results before pressing the “run” button. See below for more legal disclaimers,bu enough non-technical info on to the good stuff.
Configuring Mail.app
Setup of initial files,
Mail.app provides account template know as mail bundle’s to allow easy templates to be created. If you own a .Mac email address and have configured Mail.app without entering in “mail.mac.com” chances are you did so by Using the default mac.com template. Meaning you only had to enter in your Account ID , Full Name and Reply Address.
--Screen Shot Mail.app setup screen.
These templates live in /Library/Mail/AccountTypes/ by default. They are folders named using the reverse java name naming covetions found in most preferences in the syste,so com.mac.mailaccounts is mac.com’s template.The first step in creating a template is to create a folder using this convention i.e. “org.wallcity.mailaccounts” .We will talk about about where this will live and the permissions required in the next two sections for right now you can throw it anywhere,like your desktop.
If you take a look at the structure of /Library/Mail/AccountTypes/com.mac.mailaccounts/ you can see that inside the folder we have some localized folders such and English.lproj and French.lproj which mainly relate to language specific setting primarily relating to the name presented in fig A. The real meat of this “bundle” however is the MailAccounts.plist a XML based preference containing all of the settings you would like to configure the account with and wether you would like optionally just supply defaults for this config allowing the user to change some settings like weather SSL is used. in fact other then the small tiff file the MailAccounts.plist is the only thing that is required to make a template. You can edit the plist using the Property List Editor installed as part of the Developer Tools in /Developer/Tools/Application/Utilities . Each field in the template has a specific type respective to the information it will contain. For instance a number such as the port your smtp server runs on is the type “integer” and can only contain whole numbers. While the human readable name for the account itself is a string or a type that can contain letters and numbers. You can create this keyname(type)=value from scratch for the settings out lined in Fig C but a less work intensive option is to make a copy of the Apple supplied and place in the folder created earlier. Using this method you can change the fields to match your values and add any missing values your self. This may also help you if you are new to the Property list editor.
--insert chart and note about special folders!
The only down side of using of using the .Mac template is as you can see above according to the chart it two unique identifiers know as a Generated UID or GUID,this 128 bit number is how the system tracks these accounts. One of these is used for the account as a whole and the other in the SMTP server.More importantly as you can see it is a specific format and duplicating it between accounts could lead to undesirable results so we will need to generate a new one. This can be done with the uuidgen tool.
/usr/bin/uuidgen
B279B3D6-E9CF-4506-808A-375662C89D7C
/usr/bin/uuidgen
50644558-D382-4499-B173-1DE9251A8F3C
Running the command twice will give us two new unique identifiers we can cut in paste in those two fields in any order we like. There is no problem generating this identifier on your production computer and deploying to your workstations,and having every account template has the same GUID, this kind of configuration will work fine which is evident as all “.Mac” templates share the GUID among all 10.4 Mac’s com.mac.mailaccounts bundle.The uuidgen command can be run as many times as you like,it will provide a unique value covered more in depth by reading its man page.
After you have generated a new GUID and modified your template to match your specific mail settings your basically ready to go.The last piece of good measure is the .tiff file mentioned earlier,this a a 128x128--fix pixel logo graphic displayed next to your “Templates Name”. You can use your favorite photo editor to resize you company logo to this size,however be aware to make things look nice you might want include a alpha layer like com.mac.tiff,or just cut and paste your graphic on top the applied tiff,or just rename the .Mac to your reverse java name .tiff
--little screen shot of tiff file
Now for testing purpose’s you can throw your file in /Library/Mail/AccountTypes/ and open up or re-open mail to see the account template show up either in the setup assistant if you have never configured mail or by retroactively accesing the assistant with the plus button in accounts.If everything worked and a template if all your deployment if going to contain you can move on the one of the respective sections below. Once you have verified it works yeah can move it back of AccountTypes and move on to one of the deployment sections, or read on for an introduction to increasing value with scripting.
--plus button with big cursor graphic -- wallcity logo
Setup script introduction
( you can script this and go right to a outline of the supplied example in section 7-A)
Now lets talk about a slightly different methodology which can be used in conjunction or independent of templates. In this method we will use a (Apple/Shell) Script which has the distinction of being interactive and allows you test the limited input your users are entering in. For instance,the template above does not really provide feedback if the user enters in their account ID in the wrong format or if they ignore the visual indicator and enters in their email address instead their Account IDs.Common errors may have to do with entering in the account-ID in the wrong case,what if the user has already has setup Mail.app and is now moving to entourage cant our script just grab that username? First a little background about our primary mechanism for configuring accounts: Apple Script. Apple Script is normally billed as a “English Like” language ,most of its syntax is based around the idea of a sentence,though as most developer discover as they delve into write anything beyond basic script that its nature of sounding like English can at times be counter productive. The normal example of this is the code compiling in such a way that the nun who taught me English would fail slap me hand for. That said getting around semantical and esoteric concerns applescript does something that no System admin can ignore,it can talk to programs like Mail and enter in information using code supplied by the original developer( known in the applescript lexicon as a Dictionary). This means we dont have to write raw preferences editor type scripts that could out of date as fast a parachute pants because of a version change or a feature being added thus changing the original format and or option in the pref. A quick look at the dictionary supplied by Mail show’s a an account object capable of handling values much like our mail bundle.
-- Mail.app AppleScript Dictionary
The idea of doing programing a setup template in Apple Script seem all the more feature rich when we discover that it is cable of running routines and doing basic text manipulation. More importantly for those of you who work in your shell as much as your cubicle, you will be happy to know two things: one is that using the Apple Script command “do shell script” you can run shell commands and two that you can trade the output and input of these commands back and forth is Applescript in variable's used in your Apple Script. While this does cause a little bit of double commented text thats harder to read it also acts as a supplemental layer for your script so you can perform things that neither shell programming or Apple Script can easily do alone. So a basic script for mail setup would contain a few things in practice:
Checking for the account ID’s structure by delimiter if any “.” “_”
Checking for the correct case (normally lower for account IDs)
Checking for the character limit in the account IDs (not as common)
Finally checking for common mistakes like entering a email address
or other variations like SAM conventions in Active Directory
Well normally its the top two items that take the longest,given basic error checking and syntax tools are written to expect values that are potentially random, for instance a typo or a user entering in a email address in the wrong field such as the Account ID.Item number 3 is that one is in actually almost completely done for you due to Apple’s own Apple Script staff. In the /Library/Scripts folder you will find items used by the Script Editors #Link# Script menu preference. Of particular interest are two items Named “Create New Mail Account.scp” and “Create New LDAP Server.scpt” these give the basic syntax for building your own script in Mail.app. Looking back to the dictionary listed above you can reverse engineer these scripts to make a more basic script cable of asking the user for some information and making a new account based around that information.
I am intentionally simplifying the idea of doing this as I am providing some example scripts that are more tailored to the purpose of this article. I will tell you though that I did not start really using Apple Script Syntax until writing this article and even then I still have not saturated it capabilities. I had used of-course it as a problem solving tool with one liners and single purpose scripts for instance with ARD missing a change volume command like it predecessor (ANAT) I would use something like “osascript -e ‘set volume’ to send a UNIX->AppleScript Command or to solve actions that where tedious and easy to automate but like many IT folks using Apple script day to day eluded me mainly because of it english like nature seemed cumbersome in more complex scripts It was also too “simple” that I refused to research it, confident in my ability to speak my native tongue not able to spread my ideas around its syntax. So simple it seemed that it wasn’t until forced to use it for things like repeating subroutines that I finally cracked open my O’rielly book again instead of assuming that I knew how to use it inherently..
So its more then possible given some (hopefully) good examples and a working knowledge of Mac OS X that you too can architect something that will work in for your particular environment,Apple Script can be bizarre but when you look at a script to enter in account information,mostly its a four sentence affair that grows only larger by you willingness of available time to build in error checks, which to be far don’t exsist
(Section 7-A)
-- Outline of Mail.app Example Script.
While going through every line of my script is better suited by the semi logical variable names and comments “--”&“(*_)” found in the script its self. A basic match up its components or “_handlers” is presented below next to the three chunks introduced early on in the article
Checking for the account ID’s structure by delimiter if any “.” “_”
Checking for the correct case (normally lower for account IDs)
Checking for the character limit in the account IDs (not as common)
Finally checking for common mistakes like entering a email address
or other variations like SAM conventions in Active Directory
A quick jaunt in to package installers.
--Screen shot galore.
Building packages is some thing many administrators eventually find to be a helpful
for pushing out files/folders to basically anywhere the user running the install can access.These packages can also be pushed out via the Apple Remote Desktop software allowing for unattended or even background installs.
Creating Package Install is surprisingly easy especially using the developer new tools.
Lets break it in to three to steps for simplicity:
Deciding where you want things installed and creating a structure to mirror that.
Coping your items to this structure and noting permissions and post actions.
Building and Deploying your package and filling the gaps with documentation
Testing is always an important thing in line with measure twice cut once.
Remember its not
--Mail icon -- Deploying our Templates and Script for Mail.app
Deploying for One User local User
The package method with Mail Bundles
Deciding where you want things installed and creating a structure to mirror that.
The Account Template
for just one user mail bundles can be installed in to
~/Library/Mail/Account Types/
# note that this folder is not there by default
as noted earlier install items in the home folder. typically need to be installed into an intermediary location like /tmp/myinstaller and moved using variables in the post action scripts of the installer.
Coping your items to this structure and noting permissions and post actions.
So in my fauxroot I create /tmp/Account Types/ so my script can move it to
~/Library/Mail/Account Types/ which will make it accecible to only the
currently logged in user and will require no authentication to install
mv /tmp/Account Types/ $USER/Library/Mail/Account Types/
Building and Deploying your package and filling the gaps with documentation
documentation ,special folders with mail.
to reboot or not reboot?
disk image internet enable
Because your script must be run not necessarily be installed you can place it or install it anywhere it can run,even a thumb drive! Also the idea of the “setup” script is that is it will probably only ever be run once so having it in a more central location like posted on a webserver,may not be a bad thing for versioning copies in case you make updates.
To post your script on a server you will first want to save it as a application,so all your users will have to do to run it is double click on its icon,this can be done after you are done making your changes in the script editor by choosing
Save>As Application and un-checking “stay up” for good measure.
-- save as screen shot in script editor
We then can create a folder that will be the basis of a our Disk image are about to create,we can then move/copy our saved application into this folder
--Folder created?
Using the Disk Utility we can create a “New> Disk Image from Folder”
selecting the root of the folder we create above and saving on our desktop.
note an odd behaviour in some versions of disk utility presents the folder
you are creating the dmg from as also the save location,just pick Desktop.
Last but not least lets make this dmg internet enabled just like we did our template above,so it will shed its skin upon download only leaving the application our users to click on and run.
Deploying for All Local Users
The Search Path: Mail bundles for all!
As I am sure you have already guessed in testing your new bundle if you place it in /Library/Mail/Account Types/ all users on the local the system can see it.
-- two users side by side screen shot.
As this folder is a static value and already exists on a standard v10.4 system to deploying a bundle for all users you simply need create it in your fauxroot with place holders for /Library/Mail/Account Types/ and make sure the installer has been set to require administration privileges as /Library is writable only by admins
No post action is required as you don’t need to move anything around, For good measure you might want to however to think about removing or overwriting the default “.Mac” MailAccounts.plist so your list will show your companies bund first in the pop up menu,this can be done pretty easily by modifing the Blank field
The User Template: Skeletons in Mac OS X’s closet.
Have you ever wondered where the default folder structure comes from like Movies,Picture etc.Well when a new user is create the folders/files are copied in the case of english from /System/Library/User Template/English.lproj.
The folders (and permissions) become the basis of all newly created users,so if you would like everyone to have a folder called “Work” in all new users home directorys you can pretty easily do so by modified the contents of this folder.
Doing so requires Root access and can be done using the graphical interface if the root account is “enabled” by virtue of its password being set or via the command line privilege elevator sudo so I can copy in my “Work” folder by typing in sudo cp /path/to/Work /System/Library/User Template/English.lproj/
You may want to check the resulting permissions ( and ownership ) for security to check that the resulting items can be read and written to be only the user, and not modified further by other malicious local user,though its not likely the could.
Permissions: (“700” synonymous with “u=rwx,g=r,o=r”)
sudo chmod -R 700 /System/Library/User Template/English.lproj/Work
Ownership: ( “0:0” synonymous with “root:wheel”)
sudo chown -R 0:0 /System/Library/User Template/English.lproj/Work
Deploying for All Network and Existing Users and (Apple Remote Desktop Clients)
Account Templates and the /Network/Library/ folder.
For those you who have Open Directory or Active Directory(w/Extended Schema) servers you have another way of providing these bundles to your users.
By virtue of Network Mounts sometimes referred to as Auto Mounts, you can mount a folder on the server under the /Network/ folder this “Library” folder is part of the standard search path for resources.So Mail will look in /Network/Library/ Mail/Account Types even though its a folder “mounted” on a remote server via AFP or NFS.This means anyone bound to your Open/Active Directory or Magic Triangle system can access these templates automatically.
The details of promoting an Open Directory Master or extending a Active direc- tory server to support mount records are beyond the scope of this article ,realize though that if you have a system like this in place all you need to do is create the local “Library” to be shared out in /Network/Library, perhaps in /Shared items/ Library or on your data volume. Make it a share point using the share this item check box in Workgroup Manager and Clicking over to the Network Mount Tab.
--tri screen shot for Sharing button,Share this item, Network mount on bottom.
If you are sharing this item via AFP guest access must be on and your bound clients wont see it until they have been at least rebooted( other methods too).
The MCX Login and Launch item method
As mentioned you can keep your script tucked away in any number of Directory’s /Library/Applications Support/ /Library/Management/ /Library/Scripts
once you decided on a location you can place musical chairs with Mail.app or create a once time Login Items Prefences and a fix up in your script.
Post action scripts and Existing Users and Apple Remote Desktop
So far we have looked at Setting up a Mail.app and Address Book individually using Apple Script affecting just the console user.We have discussed creating Mail account Bundles and modifying the default address book preference so newly created users will have a “Template” to setup IMAP and have LDAP al ready configured. What about users who where already there before the install? What about if we want to distribute the account information to workstations with no (active) console user logged in?A senerio of no console user is pretty com mon when installing a package over ARD,postflight scripts that contain variables like ~ or $HOME will not work appropriately with no console running a install in fact will probably expand to /var/root on most occasions as the root user is the effective user for ARD package installs.
Now I dont want to scare you off,but our solution is our last scripting lan guage, Which is every scripting and programming language under then sun,perl python, ruby, objective c and many more.These languages have the benefit that un-like Apple Script can easily run in the background with out a console user and have access to thousands of applications and APIs to do everything your ever wanted.That said I am not going to use ANY of them in my example.I choose bash due to the fact that some of these are older scripts I have written and that for this purpose I didn’t beyond the built-in shell constructs.
In my example below you can see a starter script that uses the defaults com mand to recursively go through the /Users/ folder and Add in a non- destructive fashion account settings for Mail.app and Address Book.
Editing preferences directly has two main concerns,
One is corruption of the file/structure/version of the plist minimized by checking the plist after editing and backing it up before any modification is made.
The other is compatibility, What is Mail.app changes its preferences structure after an update?
This is minimized by Apple Them selves, if Mail.app cant read its preference from build to build preference problems would crop on other places like Migrating from an old machine 10.4.1 to a new machine 10.4.7.While preference change between version 10.4 and 10.3 10.4.x-10.4.9 will most likely have the same preference options and format for compatibility.If your worried about the 10.5 transition and rewriting your scripts,realize that much of this auto configuration is done for you in 10.5 and so wont even be needed.
--out line of shell script.
All of the Above
Entourage
Deploying for One User local User
Deploying for All Local Users
Deploying for All Network Users.
This setup documentation is provided as-is and I am not liable for any lost data or unforeseen complication arising from using the supplied instructions or scripts. That said if you find the scripts really useful and feel like donating to my *Computer book fund,also known as the “Mac OS X Fundamentals is 70$ fund :)” you can find my pay pal here.