summaryrefslogblamecommitdiff
path: root/game/irc.rpy
blob: 668d57e9f26ca2a14abf7efb11c4616bd05e40ad (plain) (tree)
























                                                                                 
                     
                                                                                                                                
 










                                                                           

                                     








                                                                          
                                        
                         

                            
 



                                                   
 
                                         
                




                                                     
                   






                                           









                                                                     
                                                          







                                                                          
                                                              






























































                                                                                                            






                                                      






























                                                                          
                  


                   
                     


                                                  

                                                                          






                                      
                             



                                     
                                 






















                                                                                                                
                                                                      
 
                                                                    
 
#################################################################################
#     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