--- /dev/null
+#!/bin/sh
+
+EMAIL="$1"
+DOMAIN=${EMAIL##*@}
+
+QUERYFILE=$(mktemp /tmp/ewsqueryXXXXXX)
+RESULTFILE=$(mktemp /tmp/ewsresultXXXXXX)
+trap 'rm $QUERYFILE $RESULTFILE' EXIT
+
+cat > $QUERYFILE <<EOF
+<Autodiscover xmlns='http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006'>
+ <Request>
+ <EMailAddress>$EMAIL</EMailAddress>
+ <AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>
+ </Request>
+</Autodiscover>
+EOF
+
+for ATTEMPT in $DOMAIN autodiscover.$DOMAIN; do
+ if [ -n $EWSURL ]; then
+ echo Trying $ATTEMPT...
+ if curl --negotiate -u dummy: -L -H "Content-Type: text/xml" \
+ https://$ATTEMPT/autodiscover/autodiscover.xml \
+ -d @$QUERYFILE > $RESULTFILE; then
+ EWSURL="$(sed -n -e '/EwsUrl/{s/.*<EwsUrl>\(.*\)<\/EwsUrl>.*/\1/p;q}' $RESULTFILE)"
+ if [ "$EWSURL" != "" ]; then
+ echo "Found EWS URL: $EWSURL"
+ exit 0
+ fi
+ fi
+ fi
+done
+
+echo "Failed to discover EWS URL"
+exit 1
--- /dev/null
+#!/bin/sh
+
+CURLAUTH="--negotiate -u dummy:"
+# NTLM is faster, but requires your password
+
+if [ "$3" != "" ]; then
+ CURLAUTH="--ntlm -u $2:$3"
+fi
+
+EWSURL="$1"
+
+mkdir -p ~/ews-sync || exit 1
+
+OLDSYNCSTATE=$(cat ~/.ews-syncstate)
+
+QUERYFILE=$(mktemp /tmp/ewsqueryXXXXXX)
+RESULTFILE=$(mktemp /tmp/ewsresultXXXXXX)
+CHANGELIST=$(mktemp /tmp/ewsclistXXXXXX)
+trap 'rm $QUERYFILE $RESULTFILE $CHANGELIST' EXIT
+
+cat > $QUERYFILE <<EOF
+<?xml version="1.0" encoding="utf-8"?>
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
+ xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
+ <soap:Body>
+ <SyncFolderItems xmlns="http://schemas.microsoft.com/exchange/services/2006/messages">
+ <ItemShape>
+ <t:BaseShape>AllProperties</t:BaseShape>
+ </ItemShape>
+ <SyncFolderId>
+ <t:DistinguishedFolderId Id="calendar"/>
+ </SyncFolderId>
+EOF
+if [ "$OLDSYNCSTATE" != "" ]; then
+ echo "<SyncState>$OLDSYNCSTATE</SyncState>" >> $QUERYFILE
+fi
+cat >> $QUERYFILE <<EOF
+ <MaxChangesReturned>50</MaxChangesReturned>
+ </SyncFolderItems>
+ </soap:Body>
+</soap:Envelope>
+EOF
+
+MORETOCOME=false
+
+if ! curl $CURLAUTH -L -H "Content-Type: text/xml" \
+ $EWSURL -d @$QUERYFILE > $RESULTFILE; then
+ exit 1
+fi
+
+# I'm far too lazy to do proper XML parsing for a proof-of-concept
+(sed 's/\(<[^/]\)/\n\1/g' $RESULTFILE; echo) | while read LINE; do
+ case $LINE in
+ "<t:Create>"*)
+ TYPE=CREATE
+ ;;
+ "<t:Update>"*)
+ TYPE=UPDATE
+ ;;
+ "<t:Delete>"*)
+ TYPE=DELETE
+ ;;
+ "<t:ItemId "*)
+ ITEMID=$(echo $LINE | sed 's/.* Id="\([^"]*\)" .*/\1/')
+ ITEMCHANGEKEY=$(echo $LINE | sed 's/.* ChangeKey="\([^"]*\)" .*/\1/')
+
+ echo $TYPE $ITEMID $ITEMCHANGEKEY >> $CHANGELIST
+ ;;
+ *)
+ ;;
+ esac
+done
+
+if grep -q '<m:IncludesLastItemInRange>false</m:I' $RESULTFILE ; then
+ MORETOCOME=true
+fi
+
+NEWSYNCSTATE=$(sed -n '/<m:SyncState>/{s/.*<m:SyncState>\(.*\)<\/m:SyncState>.*/\1/p}' $RESULTFILE)
+
+
+cat $CHANGELIST | while read TYPE ITEMID ITEMCHANGEKEY; do
+ ITEMFILENAME=~/ews-sync/$(echo $ITEMID | sed s^/^%2f^g)
+ echo $TYPE $ITEMID
+ case $TYPE in
+ DELETE)
+ rm "$ITEMFILENAME"
+ ;;
+ UPDATE|CREATE)
+ cat > $QUERYFILE <<EOF
+<?xml version="1.0" encoding="utf-8"?>
+<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
+ xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
+ <soap:Body>
+ <GetItem xmlns="http://schemas.microsoft.com/exchange/services/2006/messages">
+ <ItemShape>
+ <t:BaseShape>AllProperties</t:BaseShape>
+ </ItemShape>
+ <ItemIds>
+<t:ItemId Id="$ITEMID" ChangeKey="$ITEMCHANGEKEY"/>
+ </ItemIds>
+ </GetItem>
+ </soap:Body>
+</soap:Envelope>
+EOF
+ if ! curl $CURLAUTH -L -H "Content-Type: text/xml" \
+ $EWSURL -d @$QUERYFILE > $RESULTFILE; then
+ exit 1
+ fi
+ sed 's/\(<[^/]\)/\n\1/g' $RESULTFILE > "$ITEMFILENAME"
+ ;;
+ esac
+done
+echo $NEWSYNCSTATE > ~/.ews-syncstate
+if [ "$MORETOCOME" == "true" ]; then
+ echo Restarting to fetch more items
+ exec "$0" "$1"
+fi