about summary refs log tree commit diff
path: root/ophiculus/ophiculus.py
blob: af145e8ede084b0e92e2e1745a0edaad238720b0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#!/usr/bin/env python3
import socket
import ssl
import sys
import urllib.parse

# read target url from arguments
arg = sys.argv[1]
if '//' not in arg:
    arg = '//' + arg

url = urllib.parse.urlparse(arg, scheme='gemini')
if url.scheme != 'gemini':
    sys.exit('Unable to handle scheme')

port = url.port if url.port is not None else 1965
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
context.options |= OP_NO_TLSv1 | OP_NO_TLSV1_1 | OP_NO_TLSv1_2
# ignore certs for now, TODO actually handle cert TOFU
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE 

# TODO AF_INET6 support
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
    with context.wrap_socket(sock, server_hostname=url.hostname) as ssock:
        # connect to server [TLS handshake occurs after connect() by default]
        ip = socket.gethostbyname(url.hostname)
        ssock.connect((ip, port))
        ssock.sendall(urlparse.urlunsplit(url) + '\r\n')

        with ssock.makefile() as io:
            header = io.readline()
            print(header)
            status, meta = header.split(' ', 1)
            switch = status[0]
            if switch == '1':
                query = urllib.parse.quote(input('server requesting input: ' + meta))
                # TODO retry request
            else if switch == '2':
                # meta is mime type
                # TODO handle text/gemini i guess?
                if meta.startswith('text/'):
                    body = io.read()
                    for line in body.spiltlines():
                        print(line)
                else:
                    # TODO download file instead
                    sys.exit('didn\'t get a text file')
            else if switch == '3':
                print('temporary redirect to: ' + meta)
                # TODO prompt to follow
            else if switch == '4':
                print('temporary failure: ' + meta)
            else if switch == '5':
                print('permanent failure: ' + meta)
            else if switch == '6':
                print('client certificate required: ' + meta)
                # TODO prompt to retry
            else:
                print('unknown response: ' + meta)