#!/bin/bash
# This file is in the public domain.
set -eux

# You need to provide these (set in environment).
# PINGEN_CLIENT_ID=
# PINGEN_CLIENT_SECRET=
# PINGEN_ORG_ID=
if [ -z "${PINGEN_CLIENT_ID:-}" ]
then
    echo "PINGEN_CLIENT_ID not set in environment" 1>&2
    exit 1
fi
if [ -z "${PINGEN_CLIENT_SECRET:-}" ]
then
    echo "PINGEN_CLIENT_SECRET not set in environment" 1>&2
    exit 1
fi
if [ -z "${PINGEN_ORG_ID:-}" ]
then
    echo "PINGEN_ORG_ID not set in environment" 1>&2
    exit 1
fi

ENDPOINT="https://api.pingen.com"
LOGS="$HOME/authorization-post.log"
ERRORS="$HOME/authorization-post.err"

MESSAGE=$(cat -)
ADDR="$1"
# The address fields are handed to typst as --input values below.  Typst
# treats those strictly as strings and never as markup, so unlike with the
# LaTeX template that this script used before, no character filtering is
# needed (and none must be added: it would corrupt legitimate addresses).
# Name of business or individual, possibly with "Attn. $INDIVIDUAL_NAME"
CONTACT_NAME=$(echo "$ADDR" | jq -r .CONTACT_NAME)
# Multi-line address
ADDRESS_LINES=$(echo "$ADDR" | jq -r .ADDRESS_LINES)
# This will just be the 2-letter country code
ADDRESS_COUNTRY=$(echo "$ADDR" | jq -r .ADDRESS_COUNTRY)

case "$ADDRESS_COUNTRY"
in
	AF)
		COUNTRY='Afghanistan'
		;;
	AX)
		COUNTRY='Åland Islands'
		;;
	AL)
		COUNTRY='Albania'
		;;
	DZ)
		COUNTRY='Algeria'
		;;
	AS)
		COUNTRY='American Samoa'
		;;
	AD)
		COUNTRY='Andorra'
		;;
	AO)
		COUNTRY='Angola'
		;;
	AI)
		COUNTRY='Anguilla'
		;;
	AQ)
		COUNTRY='Antarctica'
		;;
	AG)
		COUNTRY='Antigua & Barbuda'
		;;
	AR)
		COUNTRY='Argentina'
		;;
	AM)
		COUNTRY='Armenia'
		;;
	AW)
		COUNTRY='Aruba'
		;;
	AU)
		COUNTRY='Australia'
		;;
	AT)
		COUNTRY='Austria'
		;;
	AZ)
		COUNTRY='Azerbaijan'
		;;
	BS)
		COUNTRY='Bahamas'
		;;
	BH)
		COUNTRY='Bahrain'
		;;
	BD)
		COUNTRY='Bangladesh'
		;;
	BB)
		COUNTRY='Barbados'
		;;
	BY)
		COUNTRY='Belarus'
		;;
	BE)
		COUNTRY='Belgium'
		;;
	BZ)
		COUNTRY='Belize'
		;;
	BJ)
		COUNTRY='Benin'
		;;
	BM)
		COUNTRY='Bermuda'
		;;
	BT)
		COUNTRY='Bhutan'
		;;
	BO)
		COUNTRY='Bolivia'
		;;
	BA)
		COUNTRY='Bosnia & Herzegovina'
		;;
	BW)
		COUNTRY='Botswana'
		;;
	BV)
		COUNTRY='Bouvet Island'
		;;
	BR)
		COUNTRY='Brazil'
		;;
	IO)
		COUNTRY='British Indian Ocean Territory'
		;;
	VG)
		COUNTRY='British Virgin Islands'
		;;
	BN)
		COUNTRY='Brunei'
		;;
	BG)
		COUNTRY='Bulgaria'
		;;
	BF)
		COUNTRY='Burkina Faso'
		;;
	BI)
		COUNTRY='Burundi'
		;;
	KH)
		COUNTRY='Cambodia'
		;;
	CM)
		COUNTRY='Cameroon'
		;;
	CA)
		COUNTRY='Canada'
		;;
	CV)
		COUNTRY='Cape Verde'
		;;
	BQ)
		COUNTRY='Caribbean Netherlands'
		;;
	KY)
		COUNTRY='Cayman Islands'
		;;
	CF)
		COUNTRY='Central African Republic'
		;;
	TD)
		COUNTRY='Chad'
		;;
	CL)
		COUNTRY='Chile'
		;;
	CN)
		COUNTRY='China'
		;;
	CX)
		COUNTRY='Christmas Island'
		;;
	CC)
		COUNTRY='Cocos'
		;;
	CO)
		COUNTRY='Colombia'
		;;
	KM)
		COUNTRY='Comoros'
		;;
	CG)
		COUNTRY='Congo - Brazzaville'
		;;
	CD)
		COUNTRY='Congo - Kinshasa'
		;;
	CK)
		COUNTRY='Cook Islands'
		;;
	CR)
		COUNTRY='Costa Rica'
		;;
	CI)
#shellcheck disable=SC1112
		COUNTRY='Côte d’Ivoire'
		;;
	HR)
		COUNTRY='Croatia'
		;;
	CU)
		COUNTRY='Cuba'
		;;
	CW)
		COUNTRY='Curaçao'
		;;
	CY)
		COUNTRY='Cyprus'
		;;
	CZ)
		COUNTRY='Czechia'
		;;
	DK)
		COUNTRY='Denmark'
		;;
	DJ)
		COUNTRY='Djibouti'
		;;
	DM)
		COUNTRY='Dominica'
		;;
	DO)
		COUNTRY='Dominican Republic'
		;;
	EC)
		COUNTRY='Ecuador'
		;;
	EG)
		COUNTRY='Egypt'
		;;
	SV)
		COUNTRY='El Salvador'
		;;
	GQ)
		COUNTRY='Equatorial Guinea'
		;;
	ER)
		COUNTRY='Eritrea'
		;;
	EE)
		COUNTRY='Estonia'
		;;
	SZ)
		COUNTRY='Eswatini'
		;;
	ET)
		COUNTRY='Ethiopia'
		;;
	FK)
		COUNTRY='Falkland Islands'
		;;
	FO)
		COUNTRY='Faroe Islands'
		;;
	FJ)
		COUNTRY='Fiji'
		;;
	FI)
		COUNTRY='Finland'
		;;
	FR)
		COUNTRY='France'
		;;
	GF)
		COUNTRY='French Guiana'
		;;
	PF)
		COUNTRY='French Polynesia'
		;;
	TF)
		COUNTRY='French Southern Territories'
		;;
	GA)
		COUNTRY='Gabon'
		;;
	GM)
		COUNTRY='Gambia'
		;;
	GE)
		COUNTRY='Georgia'
		;;
	DE)
		COUNTRY='Germany'
		;;
	GH)
		COUNTRY='Ghana'
		;;
	GI)
		COUNTRY='Gibraltar'
		;;
	GR)
		COUNTRY='Greece'
		;;
	GL)
		COUNTRY='Greenland'
		;;
	GD)
		COUNTRY='Grenada'
		;;
	GP)
		COUNTRY='Guadeloupe'
		;;
	GU)
		COUNTRY='Guam'
		;;
	GT)
		COUNTRY='Guatemala'
		;;
	GG)
		COUNTRY='Guernsey'
		;;
	GN)
		COUNTRY='Guinea'
		;;
	GW)
		COUNTRY='Guinea-Bissau'
		;;
	GY)
		COUNTRY='Guyana'
		;;
	HT)
		COUNTRY='Haiti'
		;;
	HM)
		COUNTRY='Heard & McDonald Islands'
		;;
	HN)
		COUNTRY='Honduras'
		;;
	HK)
		COUNTRY='Hong Kong SAR China'
		;;
	HU)
		COUNTRY='Hungary'
		;;
	IS)
		COUNTRY='Iceland'
		;;
	IN)
		COUNTRY='India'
		;;
	ID)
		COUNTRY='Indonesia'
		;;
	IR)
		COUNTRY='Iran'
		;;
	IQ)
		COUNTRY='Iraq'
		;;
	IE)
		COUNTRY='Ireland'
		;;
	IM)
		COUNTRY='Isle of Man'
		;;
	IL)
		COUNTRY='Israel'
		;;
	IT)
		COUNTRY='Italy'
		;;
	JM)
		COUNTRY='Jamaica'
		;;
	JP)
		COUNTRY='Japan'
		;;
	JE)
		COUNTRY='Jersey'
		;;
	JO)
		COUNTRY='Jordan'
		;;
	KZ)
		COUNTRY='Kazakhstan'
		;;
	KE)
		COUNTRY='Kenya'
		;;
	KI)
		COUNTRY='Kiribati'
		;;
	KW)
		COUNTRY='Kuwait'
		;;
	KG)
		COUNTRY='Kyrgyzstan'
		;;
	LA)
		COUNTRY='Laos'
		;;
	LV)
		COUNTRY='Latvia'
		;;
	LB)
		COUNTRY='Lebanon'
		;;
	LS)
		COUNTRY='Lesotho'
		;;
	LR)
		COUNTRY='Liberia'
		;;
	LY)
		COUNTRY='Libya'
		;;
	LI)
		COUNTRY='Liechtenstein'
		;;
	LT)
		COUNTRY='Lithuania'
		;;
	LU)
		COUNTRY='Luxembourg'
		;;
	MO)
		COUNTRY='Macao SAR China'
		;;
	MG)
		COUNTRY='Madagascar'
		;;
	MW)
		COUNTRY='Malawi'
		;;
	MY)
		COUNTRY='Malaysia'
		;;
	MV)
		COUNTRY='Maldives'
		;;
	ML)
		COUNTRY='Mali'
		;;
	MT)
		COUNTRY='Malta'
		;;
	MH)
		COUNTRY='Marshall Islands'
		;;
	MQ)
		COUNTRY='Martinique'
		;;
	MR)
		COUNTRY='Mauritania'
		;;
	MU)
		COUNTRY='Mauritius'
		;;
	YT)
		COUNTRY='Mayotte'
		;;
	MX)
		COUNTRY='Mexico'
		;;
	FM)
		COUNTRY='Micronesia'
		;;
	MD)
		COUNTRY='Moldova'
		;;
	MC)
		COUNTRY='Monaco'
		;;
	MN)
		COUNTRY='Mongolia'
		;;
	ME)
		COUNTRY='Montenegro'
		;;
	MS)
		COUNTRY='Montserrat'
		;;
	MA)
		COUNTRY='Morocco'
		;;
	MZ)
		COUNTRY='Mozambique'
		;;
	MM)
		COUNTRY='Myanmar'
		;;
	NA)
		COUNTRY='Namibia'
		;;
	NR)
		COUNTRY='Nauru'
		;;
	NP)
		COUNTRY='Nepal'
		;;
	NL)
		COUNTRY='Netherlands'
		;;
	NC)
		COUNTRY='New Caledonia'
		;;
	NZ)
		COUNTRY='New Zealand'
		;;
	NI)
		COUNTRY='Nicaragua'
		;;
	NE)
		COUNTRY='Niger'
		;;
	NG)
		COUNTRY='Nigeria'
		;;
	NU)
		COUNTRY='Niue'
		;;
	NF)
		COUNTRY='Norfolk Island'
		;;
	KP)
		COUNTRY='North Korea'
		;;
	MK)
		COUNTRY='North Macedonia'
		;;
	MP)
		COUNTRY='Northern Mariana Islands'
		;;
	NO)
		COUNTRY='Norway'
		;;
	OM)
		COUNTRY='Oman'
		;;
	PK)
		COUNTRY='Pakistan'
		;;
	PW)
		COUNTRY='Palau'
		;;
	PS)
		COUNTRY='Palestinian Territories'
		;;
	PA)
		COUNTRY='Panama'
		;;
	PG)
		COUNTRY='Papua New Guinea'
		;;
	PY)
		COUNTRY='Paraguay'
		;;
	PE)
		COUNTRY='Peru'
		;;
	PH)
		COUNTRY='Philippines'
		;;
	PN)
		COUNTRY='Pitcairn Islands'
		;;
	PL)
		COUNTRY='Poland'
		;;
	PT)
		COUNTRY='Portugal'
		;;
	PR)
		COUNTRY='Puerto Rico'
		;;
	QA)
		COUNTRY='Qatar'
		;;
	RE)
		COUNTRY='Réunion'
		;;
	RO)
		COUNTRY='Romania'
		;;
	RU)
		COUNTRY='Russia'
		;;
	RW)
		COUNTRY='Rwanda'
		;;
	WS)
		COUNTRY='Samoa'
		;;
	SM)
		COUNTRY='San Marino'
		;;
	ST)
		COUNTRY='São Tomé & Príncipe'
		;;
	SA)
		COUNTRY='Saudi Arabia'
		;;
	SN)
		COUNTRY='Senegal'
		;;
	RS)
		COUNTRY='Serbia'
		;;
	SC)
		COUNTRY='Seychelles'
		;;
	SL)
		COUNTRY='Sierra Leone'
		;;
	SG)
		COUNTRY='Singapore'
		;;
	SX)
		COUNTRY='Sint Maarten'
		;;
	SK)
		COUNTRY='Slovakia'
		;;
	SI)
		COUNTRY='Slovenia'
		;;
	SB)
		COUNTRY='Solomon Islands'
		;;
	SO)
		COUNTRY='Somalia'
		;;
	ZA)
		COUNTRY='South Africa'
		;;
	GS)
		COUNTRY='South Georgia & South Sandwich Islands'
		;;
	KR)
		COUNTRY='South Korea'
		;;
	SS)
		COUNTRY='South Sudan'
		;;
	ES)
		COUNTRY='Spain'
		;;
	LK)
		COUNTRY='Sri Lanka'
		;;
	BL)
		COUNTRY='St. Barthélemy'
		;;
	SH)
		COUNTRY='St. Helena'
		;;
	KN)
		COUNTRY='St. Kitts & Nevis'
		;;
	LC)
		COUNTRY='St. Lucia'
		;;
	MF)
		COUNTRY='St. Martin'
		;;
	PM)
		COUNTRY='St. Pierre & Miquelon'
		;;
	VC)
		COUNTRY='St. Vincent & Grenadines'
		;;
	SD)
		COUNTRY='Sudan'
		;;
	SR)
		COUNTRY='Suriname'
		;;
	SJ)
		COUNTRY='Svalbard & Jan Mayen'
		;;
	SE)
		COUNTRY='Sweden'
		;;
	CH)
		COUNTRY='Switzerland'
		;;
	SY)
		COUNTRY='Syria'
		;;
	TW)
		COUNTRY='Taiwan'
		;;
	TJ)
		COUNTRY='Tajikistan'
		;;
	TZ)
		COUNTRY='Tanzania'
		;;
	TH)
		COUNTRY='Thailand'
		;;
	TL)
		COUNTRY='Timor-Leste'
		;;
	TG)
		COUNTRY='Togo'
		;;
	TK)
		COUNTRY='Tokelau'
		;;
	TO)
		COUNTRY='Tonga'
		;;
	TT)
		COUNTRY='Trinidad & Tobago'
		;;
	TN)
		COUNTRY='Tunisia'
		;;
	TR)
		COUNTRY='Turkey'
		;;
	TM)
		COUNTRY='Turkmenistan'
		;;
	TC)
		COUNTRY='Turks & Caicos Islands'
		;;
	TV)
		COUNTRY='Tuvalu'
		;;
	UM)
		COUNTRY='U.S. Outlying Islands'
		;;
	VI)
		COUNTRY='U.S. Virgin Islands'
		;;
	UG)
		COUNTRY='Uganda'
		;;
	UA)
		COUNTRY='Ukraine'
		;;
	AE)
		COUNTRY='United Arab Emirates'
		;;
	GB)
		COUNTRY='United Kingdom'
		;;
	US)
		COUNTRY='United States'
		;;
	UY)
		COUNTRY='Uruguay'
		;;
	UZ)
		COUNTRY='Uzbekistan'
		;;
	VU)
		COUNTRY='Vanuatu'
		;;
	VA)
		COUNTRY='Vatican City'
		;;
	VE)
		COUNTRY='Venezuela'
		;;
	VN)
		COUNTRY='Vietnam'
		;;
	WF)
		COUNTRY='Wallis & Futuna'
		;;
	EH)
		COUNTRY='Western Sahara'
		;;
	YE)
		COUNTRY='Yemen'
		;;
	ZM)
		COUNTRY='Zambia'
		;;
	ZW)
		COUNTRY='Zimbabwe'
		;;
    *)
        echo "ERROR: Country code '${ADDRESS_COUNTRY}' not recognized" 1>&2
        COUNTRY="${ADDRESS_COUNTRY}"
        ;;
esac

MYDIR=$(mktemp -d "/tmp/${USER:-$(id -un)}-challenger-postal-generator-XXXXXX")
# The working directory is removed at the very end of this script, and only
# there: if anything fails we deliberately leave it behind, as letter.typ, the
# rendered letter.pdf and the API replies are what one needs to diagnose the
# failure.  This trap merely records where they were kept; it is disarmed
# before the successful cleanup below.
trap 'echo "challenger-send-post failed, working files kept in ${MYDIR}" >> "$ERRORS"' EXIT
cd "$MYDIR"

# The letter template.
# pingen prints the addressee through the window of the envelope and is
# therefore picky about where the address block sits.  Do not move the
# addressee, the date or the subject without re-checking that.
#
# --ignore-system-fonts keeps rendering reproducible and fast: "New Computer
# Modern" (the OpenType successor of the Computer Modern that pdflatex used
# here) ships inside the typst binary.  Drop that flag or add --font-path if
# addresses in non-Latin scripts ever need to be printed.
cat > letter.typ <<'ENDOFLETTERTEMPLATE'
// Geometry measured from the scrlttr2 letter this replaced; scripts/test-pdf.sh
// renders the same letter without uploading it, for checking changes.
#let FS = 10.9091pt          // effective size of cmr10 in the 11pt letter
#let LEAD = 0.242035em       // baseline step = 1.242035em = 13.5495pt
#let TW = 416.705pt          // text width  (31.50mm .. 178.50mm)
#let TX = 89.291pt           // text left   (31.50mm)
#let AX = 85.039pt           // address left (30mm, = toaddrhpos)
#let AW = 240.945pt          // address width (85mm, = toaddrwidth)
#let ACENTER = 203.647pt     // address block is centred on this baseline
#let ACLAMP = 152.16pt       // ... unless it is too tall, then it starts here
#let DATE_BL = 292.762pt
#let SUBJ_BL = 319.860pt
#let OPEN_BL = 360.508pt
#let BODY_BL = 387.606pt
#let CLOSE_GAP = 26.151pt    // last body baseline -> closing baseline
#let SIG_GAP = 40.648pt      // closing baseline -> signature baseline
#let BOTTOM_BL = 672.19pt    // last baseline that still fits on page 1

#let SIGNATURE = "Taler Operations AG, c/o Berner Fachhochschule, Höheweg 80, 2502 Biel/Bienne"
#let SUBJECT = "Address validation"
#let OPENING = "To whom it may concern,"
#let CLOSING = "Best regards"

#set page(paper: "a4", margin: 0pt)
#set text(
  font: "New Computer Modern",
  size: FS,
  top-edge: 0.75em,
  bottom-edge: -0.25em,
  lang: "en",
  hyphenate: false,
)
#set par(leading: LEAD, spacing: LEAD, justify: true)

// place a block so that its *first baseline* lands on `bl`
#let at-baseline(x, bl, body) = place(top + left, dx: x, dy: bl - 0.75em, body)

#let name = sys.inputs.at("name", default: "")
#let addr = sys.inputs.at("addr", default: "")
#let country = sys.inputs.at("country", default: "")
#let message = sys.inputs.at("message", default: "")

// ---- addressee -----------------------------------------------------------
// TeX collapses runs of whitespace; a multi-line name becomes a single line.
#let flat(s) = s.replace(regex("\\s+"), " ").trim()
#let addr-lines = (
  ((flat(name),) + addr.split("\n").map(flat) + (flat(country),)).filter(l => l != "")
)
#let addr-block = block(width: AW)[
  #set par(justify: false)
  #addr-lines.join(linebreak())
]

#context {
  let h = measure(addr-block).height
  let bl = calc.max(ACLAMP, ACENTER - (h - FS) / 2)
  at-baseline(AX, bl, addr-block)
}

// ---- reference line, subject, opening ------------------------------------
#at-baseline(TX, DATE_BL, block(width: TW, align(right, datetime.today().display(
  "[month repr:long] [day padding:none], [year]",
))))
#at-baseline(TX, SUBJ_BL, text(weight: "bold", SUBJECT))
#at-baseline(TX, OPEN_BL, OPENING)

// ---- body ----------------------------------------------------------------
// TeX collapses runs of whitespace and starts a new paragraph on a blank line.
#let paragraphs = message.split(regex("\n[ \t]*\r?\n")).map(p => p.replace(
  regex("\\s+"),
  " ",
).trim()).filter(p => p != "")

#let body-at(scale) = block(width: TW)[
  #set text(size: FS * scale, hyphenate: true)
  #set par(first-line-indent: (amount: 1em, all: false))
  #for p in paragraphs [#par(p)]
]

#context {
  // Shrink the body until closing and signature still fit on this page.
  let scale = 1.0
  let fits(s) = {
    let last = BODY_BL + (measure(body-at(s)).height - FS * s)
    last + CLOSE_GAP + SIG_GAP <= BOTTOM_BL
  }
  while scale > 0.34 and not fits(scale) {
    scale -= 0.02
  }
  if not fits(scale) {
    panic("challenge message is far too long to fit on one A4 page")
  }

  at-baseline(TX, BODY_BL, body-at(scale))

  // ---- closing and signature ---------------------------------------------
  // scrlttr2 puts both in a box as wide as its widest line, left-aligned with
  // the text body, and centres each line inside that box.
  let last = BODY_BL + (measure(body-at(scale)).height - FS * scale)
  let sigw = measure(SIGNATURE).width
  let sigbox(s) = block(width: sigw, {
    set par(justify: false)
    align(center, s)
  })
  at-baseline(TX, last + CLOSE_GAP, sigbox(CLOSING))
  at-baseline(TX, last + CLOSE_GAP + SIG_GAP, sigbox(SIGNATURE))
}
ENDOFLETTERTEMPLATE

if ! typst compile \
	    --ignore-system-fonts \
	    --no-pdf-tags \
	    --input "name=$CONTACT_NAME" \
	    --input "addr=$ADDRESS_LINES" \
	    --input "country=$COUNTRY" \
	    --input "message=$MESSAGE" \
	    letter.typ letter.pdf
then
    echo "Failed to render letter for country ${ADDRESS_COUNTRY}" >> "$ERRORS"
    exit 1
fi

REPLY=$(curl \
	    -s \
	    -X POST \
	    -H "Content-Type: application/x-www-form-urlencoded" \
	    --data-urlencode "grant_type=client_credentials" \
	    --data-urlencode "client_id=$PINGEN_CLIENT_ID" \
	    --data-urlencode "client_secret=$PINGEN_CLIENT_SECRET" \
	    --data-urlencode "scope=letter" \
	    https://identity.pingen.com/auth/access-tokens)

ACCESS_TOKEN=$(echo "$REPLY" | jq -r .access_token)

REPLY=$(curl -s \
    -X GET "$ENDPOINT/file-upload" \
    -H  "Authorization: Bearer $ACCESS_TOKEN")
ATTRS=$(echo "$REPLY" | jq .data.attributes)
UPLOAD_URL=$(echo "$ATTRS" | jq -r .url)
URL_SIG=$(echo "$ATTRS" | jq -r .url_signature)

STATUS=$(curl -s \
     -X PUT \
     -T letter.pdf \
     "$UPLOAD_URL" \
     -o "$MYDIR/upload-status.txt" \
     -w "%{http_code}" -s)

case "$STATUS" in
    200)
        ;;
    201)
        ;;
    204)
        ;;
    *)
        echo "Failed to upload letter: $STATUS" >> "$ERRORS"
        cat "$MYDIR/upload-status.txt" >> "$ERRORS"
        exit 1;
        ;;
esac


REQUEST="$(jq -n '
    {   data: {
        type: "letters",
	attributes: {
	  file_original_name: "letter.pdf",
	  file_url: $UPLOAD_URL,
	  file_url_signature: $URL_SIG,
	  address_position: "left",
	  delivery_product: "cheap",
	  print_mode: "duplex",
	  auto_send: true,
 	  print_spectrum: "grayscale"
        } }
    }' \
    --arg UPLOAD_URL "$UPLOAD_URL" \
    --arg URL_SIG "$URL_SIG" \
  )"

STATUS=$(curl -s \
     --request POST \
     --url "$ENDPOINT/organisations/${PINGEN_ORG_ID}/letters" \
     --header "Content-Type: application/vnd.api+json" \
     --header "Authorization: Bearer $ACCESS_TOKEN" \
     -d "$REQUEST" \
     -o "$MYDIR/final-reply.txt" \
     -w "%{http_code}" -s)
case "$STATUS" in
    201)
        cat "$MYDIR/final-reply.txt" >> "$LOGS"
        ;;
    *)
        echo "Failed to add letter: $STATUS" >> "$ERRORS"
        cat "$MYDIR/final-reply.txt" >> "$ERRORS"
        exit 1;
        ;;
esac

# The letter was accepted by pingen: this is the only success path, so this
# is the only place where the working directory gets cleaned up.
trap - EXIT
cd /
rm -r "$MYDIR"
exit 0
