summaryrefslogtreecommitdiff
path: root/gemini.py
blob: c0d09c11757995ca59742a610bdd39c94a28821d (plain)
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import socket
import ssl

def htmlescape(text):
    return text.replace('<', '&lt;').replace('>', '&gt;')

def gem2html(gem):
    html = []
    state = 'text'
    blanklines = 0
    for line in gem.split('\n'):
        if line.startswith('```'):
            if state == 'pre':
                newstate = 'text'
                blanklines = 0
            else:
                newstate = 'pre'
        elif state == 'pre':
            newstate = 'pre'
        elif line.startswith('=>'):
            newstate = 'links'
        elif line.startswith('* '):
            newstate = 'list'
        else:
            newstate = 'text'

        if state != 'pre':
            if len(line.strip()) == 0:
                blanklines += 1
                if blanklines > 1:
                    html.append('<br/>')
                continue
            blanklines = 0

        if state != newstate:
            if state in ('links', 'list'):
                html.append('</ul>')
            elif state == 'pre':
                html.append('</pre>')

            if newstate in ('links', 'list'):
                html.append('<ul>')
            elif newstate == 'pre':
                html.append('<pre>')
        state = newstate

        if line.startswith('```'):
            pass
        elif state == 'links':
            tokens = line.split(None, 2)
            if len(tokens) == 3:
                _, url, text = tokens
                html.append('<li><a href="{url}">{text}</a></li>'.format(url=url, text=text))
            else:
                _, url = tokens
                html.append('<li><a href="{url}">{url}</a></li>'.format(url=url))
        elif state == 'list':
            html.append('<li>{}</li>'.format(line[2:]))
        elif state == 'pre':
            html.append(line)
        else:
            if line.startswith('###'):
                html.append('<h3>{}</h3>'.format(line[3:].lstrip()))
            elif line.startswith('##'):
                html.append('<h2>{}</h2>'.format(line[2:].lstrip()))
            elif line.startswith('#'):
                html.append('<h1>{}</h1>'.format(line[1:].lstrip()))
            else:
                html.append('<p>{}</p>'.format(htmlescape(line)))
    return '\n'.join(html)

def absolute_url(base, url):
    """
    modifies `url` in place
    """
    if not url.scheme():
        url.setScheme(base.scheme())
    if not url.host():
        url.setHost(base.host())
    if not url.path().startswith('/'):
        url.setPath(base.path().rsplit('/', 1)[0] + '/' + url.path())
    if url.port() == -1:
        url.setPort(1965)
    return url

def get(url):
    if len(url.path()) == 0:
        url.setPath('/')
        return {
            'status': '32',
            'meta': url.toDisplayString(),
        }
    context = ssl.create_default_context()
    context.check_hostname = False
    context.verify_mode = ssl.CERT_NONE
    with socket.create_connection((url.host(), url.port())) as sock:
        with context.wrap_socket(sock, server_hostname=url.host()) as ssock:
            ssock.sendall('gemini://{}{}\r\n'.format(url.host(), url.path()).encode('utf8'))
            fp = ssock.makefile(mode='rb')
            header = fp.readline(1027)
            status, meta = header.decode('utf8').split(None, 1)
            if status[0] != '2':
                return {
                    'status': status,
                    'meta': meta.strip(),
                }
            body = fp.read()
    return {
        'status': status,
        'meta': meta.strip(),
        'body': body.decode('utf8'),
    }