-from twisted.web import resource, server, static
+from twisted.web import resource, server, static, error as http_error
from twisted.names import client
from twisted.internet import reactor, error
from authgateengine import login_optional, getSessionData
-import simplejson, md5, sys, os, time, config, weakref, traceback
+import simplejson, md5, sys, os, time, config, qwebirc.config_options as config_options, traceback, socket
import qwebirc.ircclient as ircclient
from adminengine import AdminEngineAction
from qwebirc.util import HitCounter
-
+import qwebirc.dns as qdns
Sessions = {}
def get_session_id():
class IDGenerationException(Exception):
pass
+class PassthruException(Exception):
+ pass
+
NOT_DONE_YET = None
def jsondump(fn):
x = (True, x)
except AJAXException, e:
x = (False, e[0])
+ except PassthruException, e:
+ return str(e)
return simplejson.dumps(x)
return decorator
self.id = id
self.subscriptions = []
self.buffer = []
+ self.buflen = 0
self.throttle = 0
self.schedule = None
self.closed = False
encdata = simplejson.dumps(self.buffer)
self.buffer = []
-
+ self.buflen = 0
+
newsubs = []
for x in self.subscriptions:
if x.write(encdata):
cleanupSession(self.id)
def event(self, data):
- bufferlen = sum(map(len, self.buffer))
- if bufferlen + len(data) > config.MAXBUFLEN:
+ newbuflen = self.buflen + len(data)
+ if newbuflen > config.MAXBUFLEN:
self.buffer = []
- self.client.error("Buffer overflow")
+ self.client.error("Buffer overflow.")
return
self.buffer.append(data)
+ self.buflen = newbuflen
self.flush()
def push(self, data):
reactor.callLater(5, cleanupSession, self.id)
+# DANGER! Breach of encapsulation!
+def connect_notice(line):
+ return "c", "NOTICE", "", ("AUTH", "*** (qwebirc) %s" % line)
+
class Channel:
def __init__(self, request):
self.request = request
handler = self.COMMANDS.get(path[1:])
if handler is not None:
return handler(self, request)
- raise AJAXException("404")
+
+ raise PassthruException, http_error.NoResource().render(request)
-# def render_GET(self, request):
-# return self.render_POST(request)
-
def newConnection(self, request):
ticket = login_optional(request)
- _, ip, port = request.transport.getPeer()
+ ip = request.getClientIP()
nick = request.args.get("nick")
if not nick:
- raise AJAXException("Nickname not supplied")
+ raise AJAXException, "Nickname not supplied."
nick = ircclient.irc_decode(nick[0])
- ident, realname = "webchat", config.REALNAME
-
+ password = request.args.get("password")
+ if password is not None:
+ password = ircclient.irc_decode(password[0])
+
for i in xrange(10):
id = get_session_id()
if not Sessions.get(id):
if qticket is None:
perform = None
else:
- perform = ["PRIVMSG %s :TICKETAUTH %s" % (config.QBOT, qticket)]
+ service_mask = config.AUTH_SERVICE
+ msg_mask = service_mask.split("!")[0] + "@" + service_mask.split("@", 1)[1]
+ perform = ["PRIVMSG %s :TICKETAUTH %s" % (msg_mask, qticket)]
+
+ ident, realname = config.IDENT, config.REALNAME
+ if ident is config_options.IDENT_HEX or ident is None: # latter is legacy
+ ident = socket.inet_aton(ip).encode("hex")
+ elif ident is config_options.IDENT_NICKNAME:
+ ident = nick
self.__connect_hit()
- client = ircclient.createIRC(session, nick=nick, ident=ident, ip=ip, realname=realname, perform=perform)
- session.client = client
-
+
+ def proceed(hostname):
+ kwargs = dict(nick=nick, ident=ident, ip=ip, realname=realname, perform=perform, hostname=hostname)
+ if password is not None:
+ kwargs["password"] = password
+
+ client = ircclient.createIRC(session, **kwargs)
+ session.client = client
+
+ if not hasattr(config, "WEBIRC_MODE") or config.WEBIRC_MODE == "hmac":
+ proceed(None)
+ elif config.WEBIRC_MODE != "hmac":
+ notice = lambda x: session.event(connect_notice(x))
+ notice("Looking up your hostname...")
+ def callback(hostname):
+ notice("Found your hostname.")
+ proceed(hostname)
+ def errback(failure):
+ notice("Couldn't look up your hostname!")
+ proceed(ip)
+ qdns.lookupAndVerifyPTR(ip, timeout=[config.DNS_TIMEOUT]).addCallbacks(callback, errback)
+
Sessions[id] = session
return id
def getSession(self, request):
+ bad_session_message = "Invalid session, this most likely means the server has restarted; close this dialog and then try refreshing the page."
+
sessionid = request.args.get("s")
if sessionid is None:
- raise AJAXException("Bad session ID")
+ raise AJAXException, bad_session_message
session = Sessions.get(sessionid[0])
if not session:
- raise AJAXException("Bad session ID")
+ raise AJAXException, bad_session_message
return session
def subscribe(self, request):
def push(self, request):
command = request.args.get("c")
if command is None:
- raise AJAXException("No command specified")
+ raise AJAXException, "No command specified."
self.__total_hit()
decoded = ircclient.irc_decode(command[0])
if len(decoded) > config.MAXLINELEN:
session.disconnect()
- raise AJAXException("Line too long")
+ raise AJAXException, "Line too long."
try:
session.push(decoded)
except AttributeError: # occurs when we haven't noticed an error
session.disconnect()
- raise AJAXException("Connection closed by server.")
+ raise AJAXException, "Connection closed by server; try reconnecting by reloading the page."
except Exception, e: # catch all
session.disconnect()
traceback.print_exc(file=sys.stderr)
- raise AJAXException("Unknown error.")
+ raise AJAXException, "Unknown error."
return True
}
COMMANDS = dict(p=push, n=newConnection, s=subscribe)
-
\ No newline at end of file
+