#!/usr/bin/env python
#
#  sstpsend.py - a simple SSTP client in Python
#                Tamito KAJIYAMA <23 May 2001>
#
#  $Id: sstpsend.py,v 1.5 2001/09/30 01:57:49 kajiyama Exp $
#

import getopt
import os
import socket
import string
import sys
import re

REQUESTS = {
    "SEND/1.1": (
        "SEND SSTP/1.1\r\n"
        "Sender: sstpsend.py\r\n"
        "Script: %(script)s\r\n"
        "Option: %(options)s\r\n"
        "Charset: Shift_JIS\r\n"),
    "SEND/1.2": (
        "SEND SSTP/1.2\r\n"
        "Sender: sstpsend.py\r\n"
        "Script: %(script)s\r\n"
        "Option: %(options)s\r\n"
        "Charset: Shift_JIS\r\n"),
    "EXECUTE/1.0": (
        "EXECUTE SSTP/1.0\r\n"
        "Command: GetName\r\n"
        "Sender: sstpsend.py\r\n"
        "Option: %(options)s\r\n"
        "Charset: Shift_JIS\r\n"),
    "EXECUTE/1.2": (
        "EXECUTE SSTP/1.2\r\n"
        "Command: GetVersion\r\n"
        "Sender: sstpsend.py\r\n"
        "Option: %(options)s\r\n"
        "Charset: Shift_JIS\r\n"),
    }

USAGE = """\
Usage: %(program)s [options] [-i] <script>
       %(program)s [options] -q <script> <entry1> <entry2> ...
       %(program)s [options] -n
       %(program)s [options] -v

This program sends an SSTP request to a server on the specified host
and port, and prints the SSTP response.

In the simplest form of use, sstpsend.py sends a SEND/1.1 request,
and the script specified in the command line is displayed by the
server.  If the -i (--stdin) option is specified, sstpsend.py reads
the script from the standard input instead of the command line.
The -I (--stdin-escaped) option works in the similar way but special
characters (`\\' and `%%') in the script are escaped and newlines are
replaced with \\n tags.

With the -q (--query) option, sstpsend.py sends a SEND/1.2 request.
In the script you can use a number of \\q tags.  The server will ask
the user to choose one of the alternatives and return the selected
entry.  Entries must be in the form "id,script".  You need to specify
the same number of entries as the \\q tags in the script.

With the -n (--get-name) option, sstpsend.py sends an EXECUTE/1.0
request.  The response is the name of the ghost used at the moment.

With the -v (--get-version) option, sstpsend.py sends an EXECUTE/1.2
request.  The response the server's version.

Options:
-s, --server HOST    SSTP server's host name (default: locahost)
-p, --port NUM       port number for SSTP connection (default: 9801)
-q, --query          send EXECUTE/1.2
-n, --get-name       send EXECUTE/1.0 GetName
-v, --get-version    send EXECUTE/1.2 GetVersion
-i, --stdin          read script from standard input
-I, --stdin-escaped  similar to -i but special characters are escaped
--no-sstp-marker     enable "nodescript" option
-h, --help           show this message

"""

def usage():
    sys.stderr.write(USAGE % {"program": os.path.basename(sys.argv[0])})
    sys.exit(1)

def escape(script):
    for f, t in [("\\", "\\\\"), ("%", "\\%"), ("\n", "\\n")]:
        script = string.replace(script, f, t)
    return script

def euc2sjis(s):
    return unicode(s, "euc-jp", "ignore").encode("shift_jis", "ignore")

def any2euc(s, code):
    return unicode(s, code, "ignore").encode("euc-jp", "ignore")

def main():
    try:
        options, argv = getopt.getopt(sys.argv[1:], "s:p:qnviIh",
            ["server=", "port=", "query", "get-name", "get-version",
             "stdin", "stdin-escaped", "no-sstp-marker", "help"])
    except getopt.error, e:
        sys.stderr.write("Error: %s\n" % str(e))
        usage()
    host = ""
    port = 9801
    command = "SEND/1.1"
    headers = { "options": "notranslate" }
    stdin = None
    for opt, val in options:
        if opt in ["-s", "--server"]:
            host = val
        elif opt in ["-p", "--port"]:
            port = int(val)
        elif opt in ["-q", "--query"]:
            command = "SEND/1.2"
        elif opt in ["-n", "--get-name"]:
            command = "EXECUTE/1.0"
        elif opt in ["-v", "--get-version"]:
            command = "EXECUTE/1.2"
        elif opt in ["-i", "--stdin"]:
            stdin = string.replace(sys.stdin.read(), "\n", "")
        elif opt in ["-I", "--stdin-escaped"]:
            stdin = escape(sys.stdin.read())
        elif opt == "--no-sstp-marker":
            headers["options"] = "nodescript,notranslate"
        else:
            usage()
    if command == "SEND/1.1":
        if stdin is not None:
            headers["script"] = euc2sjis(stdin)
        elif len(argv) == 1:
            headers["script"] = euc2sjis(argv[0])
        else:
            usage()
    elif command == "SEND/1.2":
        if stdin is not None:
            headers["script"] = euc2sjis(stdin)
        elif len(argv) > 0:
            headers["script"] = euc2sjis(argv[0])
        else:
            usage()
    else:
        if len(argv) > 0:
            usage()
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        s.connect((host, port))
    except socket.error, (code, message):
        sys.stderr.write(message + "\n")
        sys.exit(1)
    s.send(REQUESTS[command] % headers)
    for entry in argv[1:]:
        s.send("Entry: %s\r\n" % euc2sjis(entry))
    s.send("\r\n")
    buffer = []
    while 1:
        data = s.recv(1024)
        if not data:
            break
        buffer.append(data)
    s.close()
    response = string.join(buffer, '')
    match = re.search("^Charset: *([^\r]*)", response, re.MULTILINE)
    if match:
        code = match.group(1)
    else:
        code = "Shift_JIS"
    sys.stdout.write(any2euc(response, code))

if __name__ == "__main__":
    main()
