summaryrefslogtreecommitdiff
path: root/game/irc.rpy
blob: 668d57e9f26ca2a14abf7efb11c4616bd05e40ad (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
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
#################################################################################
#     This file is part of Spheres.
#     Copyright (C) 2019  Jesusalva

#     This library is free software; you can redistribute it and/or
#     modify it under the terms of the GNU Lesser General Public
#     License as published by the Free Software Foundation; either
#     version 2.1 of the License, or (at your option) any later version.

#     This library is distributed in the hope that it will be useful,
#     but WITHOUT ANY WARRANTY; without even the implied warranty of
#     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#     Lesser General Public License for more details.

#     You should have received a copy of the GNU Lesser General Public
#     License along with this library; if not, write to the Free Software
#     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
#################################################################################
# Chat controller
# TODO: Pub interface, using irc_send() and irc_buffer

init python:
    irc=None
    irc_online=False

    def irc_san(txt):
        return txt.replace("[", "(").replace("]", ")").replace("\n", "").replace("{", "(").replace("}", ")").replace("%", "pc.")

    def irc_open():
        if not persistent.irc_enable:
            return

        global irc, irc_buffer, irc_nick, irc_auth, irc_channel, irc_online
        import socket, sys, random

        reload(sys)
        sys.setdefaultencoding('utf8')

        irc_online=False
        server = "irc.libera.chat"
        irc_channel = "#mana-spheres"
        # TODO: Replace this with some uuid4()?
        irc_nick = "GS_" + get_token()[:3] + str(random.randint(1, 10000))
        irc_auth=IRC_AUTH_NONE
        irc_buffer=[]
        irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        stdout("\nConnecting to:" + server)
        irc.connect((server, 6667))
        return

    def irc_receive(raw, irc_sender=""):
        global irc_buffer
        if irc_sender == "":
            sender="IRC"

            # Control buffer length
            if (len(irc_buffer) >= MAX_IRC_BUFFER):
                nil=irc_buffer.pop(0)
                del nil

            # Find sender if not supplied
            try:
                p1=raw.find('<')+1
                p2=raw.find('>')
                if p2 <= p1:
                    raise Exception("Invalid sender")
                sender=raw[p1:p2]
            except:
                try:
                    p1=raw.find("!")
                    sender="IRC."+raw[1:p1]
                except:
                    sender="IRC"
        else:
            sender = irc_sender

        # Extract message
        try:
            p1=raw.find(" :") # Perhaps we're looking for ">" instead
            msg=raw[p1:]
        except:
            msg="Unparseable"

        # UNIX format
        msg=msg.replace('\r', '')
        irc_buffer.append((irc_san(sender), irc_san(msg)))
        return

    def irc_send(sender, msg):
        global irc, irc_channel, irc_online
        if not irc_online:
            return False
        try:
            irc.send("PRIVMSG %s :<%s> %s\n" % (irc_channel, sender, msg))
            irc_buffer.append((irc_san(sender), irc_san(msg)))
            return True
        except:
            return False

    def irc_kill():
        global irc, irc_online
        if irc_online:
            irc.send("QUIT :I have to go for now!\n")
            stdout("[IRC] Closing connection normally...")
            irc.shutdown(2)
            irc.close()
            irc_online=False
            stdout("[IRC] IRC Bridge is now Offline.")
        #del irc
        irc=None
        return

    def irc_loop():
        if not persistent.irc_enable:
            return

        global irc, irc_buffer, irc_nick, irc_auth, irc_channel, irc_online

        if irc is None:
            irc_open()

        try:
            while 1:
                text = irc.recv(2048)
                if len(text) > 0:
                    if debug:
                        stdout("[IRC] %s" % text)
                else:
                    continue

                # Handle ping requests
                if text.find("PING") != -1:
                    irc.send("PONG " + text.split()[1] + "\n")

                # Authentication: Step 1
                if irc_auth == IRC_AUTH_NONE:
                    irc.send("USER " + irc_nick + " " + irc_nick + " " + irc_nick + " :This is a fun bot\n")
                    irc_auth=IRC_AUTH_USER
                    continue

                # Authentication: Step 2
                if irc_auth == IRC_AUTH_USER:
                    irc.send("NICK " + irc_nick + "\n")
                    irc_auth=IRC_AUTH_NICK
                    continue

                # Authentication: Step 3
                if text.find("255 " + irc_nick) != -1:
                    irc.send("JOIN " + irc_channel + "\n")

                if text.find("376 " + irc_nick) != -1:
                    if irc_auth == IRC_AUTH_NICK:
                        irc_auth=IRC_AUTH_CHAN
                        irc_online=True
                    else:
                        stdout("[IRC] Erroneous Authentication on 376 message")
                        irc_online=True

                # Would be nice to show MOTD
                if text.find("372 " + irc_nick) != -1:
                    for line in text.split("\n"):
                        if "372" in line:
                            print("[372] %s" % line)
                            irc_receive(line, "MOTD")

                if irc_auth == IRC_AUTH_CHAN:
                    # IRC Syntax
                    # :nick!hostname PRIVMSG #tmw2-spheres :<nickname> msg
                    # We should use <nickname>, not :nick!

                    # TODO: Handle CTCP ACTION
                    if text.find(irc_channel) != -1:
                        if "PRIVMSG" in text:
                            irc_receive(text)

                    # Handle disconnections
                    if not irc_online:
                        raise Exception("Connection terminated.")

        finally:
            try:
                irc.send("QUIT :I have to go for now!\n")
                irc.shutdown(2)
                irc.close()
            except:
                stdout("[IRC] [ERROR] Connection was already closed.")
            stdout("\n")
            stdout("Closing IRC connection...")
            irc=None

        return

screen pub():
    frame:
        background Frame("gui/frame.png", 0, 0)
        xalign 0.5
        yalign 1.0
        ymargin 15
        ypadding 10
        xmargin 10
        ymaximum 0.82
        vbox:
            spacing 30
            textbutton _("Exit") action Return("")
            #label _("PUB RAID - NOT YET IMPLEMENTED")
            label _("IRC Lobby - %s at %s" % (irc_channel, "libera.chat"))
            null height 20
            viewport:
                #child_size (0.4, 0.8)
                mousewheel True
                draggable True
                arrowkeys True
                xfill False
                ymaximum 0.75
                scrollbars "vertical"

                vbox:
                    xalign 0.5
                    ymaximum 0.75
                    spacing 5
                    label _("%s" % persistent.nickname)
                    null height 40

                    showif irc_online:
                        for chat in irc_buffer:
                            label _("%s: {size=22}%s{/size}" % (chat[0], chat[1].replace("<%s>" % chat[0], "")))

                        null height 40
                        input:
                            id "msgmsg"
                            color ((128, 128, 128, 220))
                            italic True
                            size 26
                            copypaste True
                            allow "qwertyuiopasdfghjklzxcvbnm QWERTYUIOPASDFGHJKKLZXCVBNM,.?!+-=:;'()"
                        textbutton _("Send") action None # Function(irc_send)
                    else:
                        if persistent.irc_enable:
                            label _("Connecting...")
                        else:
                            label _("IRC Integration is not active.")
                        # FIXME inform if IRC is disabled
                        # Ask user to comply with Libera Chat TOS etc.

    timer 0.5 action Function(renpy.restart_interaction) repeat True