Merge pull request #130 from kiooeht/master

merge in kiooeht
This commit is contained in:
illuminatedwax 2014-10-15 02:10:05 -05:00
commit f2a482b241
15 changed files with 441 additions and 114 deletions

2
.gitignore vendored
View file

@ -1,3 +1,5 @@
*.swp
*~
logs/*
build/*
profiles/*

View file

@ -22,6 +22,10 @@ CHANGELOG
* FTP and Magnet links - oakwhiz
* Userlist search - oakwhiz
* Chanserv in menus - Cerxi [binaryCabalist]
* Lua quirks
* Multi-select memo chooser - [alGore]
* Auto-identify with NickServ - Kiooeht [evacipatedBox]
* Auto-join memos - Kiooeht [evacipatedBox]
* Bug fixes
* Don't require pygame (it's kind of optional, you just don't get sound) - Kiooeht [evacipatedBox]
* Allow add chum dialog to open after adding an existing chum - Kiooeht [evacipatedBox]
@ -32,6 +36,9 @@ CHANGELOG
* Move hidden chums when deleting group - Kiooeht [evacipatedBox]
* Don't allow rename groups with parenthesis - Kiooeht [evacipatedBox]
* Wrap long error messages - Kiooeht [evacipatedBox]
* chdir into quirks folder for Lua quirks - [alGore]
* Toast notifications don't require sound to be on - Kiooeht [evacipatedBox]
* Don't close Pesterchum if a window is closed while main window minimized - Kiooeht [evacipatedBox]
### 3.41.3

View file

@ -35,8 +35,6 @@ Bugs
* Closing a timeclone doesn't actually cease for everyone else
* Kill Zalgo
* Random invisible, tiny links to last link at end of every message
* Clicking link to invite-only memo crashes
* Close when banned from memo when main PC window minimized
* Chums not appearing on chumroll when initals are the same? (bS)
* Recognize IRC 471, 473, 474 and 475
* memo links aren't case sensitive

3
irc.py
View file

@ -176,6 +176,9 @@ class PesterIRC(QtCore.QThread):
except socket.error:
self.setConnectionBroken()
self.mainwindow.closeConversations(True)
self.mainwindow.doAutoIdentify()
self.mainwindow.autoJoinDone = False
self.mainwindow.doAutoJoins()
self.updateMood()
@QtCore.pyqtSlot()
def updateMood(self):

61
luaquirks.py Normal file
View file

@ -0,0 +1,61 @@
import os, sys, re, ostools
try:
import lua
except ImportError:
lua = None
from quirks import ScriptQuirks
from PyQt4 import QtGui, QtCore
class LuaQuirks(ScriptQuirks):
def loadModule(self, name, filename):
if lua is None:
return None
lua.globals().package.loaded[name] = None
CurrentDir = os.getcwd()
os.chdir('quirks')
try:
return lua.require(name)
except Error as e:
print e
return None
finally:
os.chdir(CurrentDir)
def getExtension(self):
return '.lua'
def modHas(self, module, attr):
return module[attr] is not None
def register(self, module):
class Wrapper(object):
def __init__(self, module, name):
self.module = module
self.name = name
def __call__(self, text):
CurrentDir = os.getcwd()
os.chdir('quirks')
try:
return self.module.commands[self.name](lua.globals().tostring(text))
except:
return None
finally:
os.chdir(CurrentDir)
for name in module.commands:
CommandWrapper = Wrapper(module,name)
try:
if not isinstance(CommandWrapper("test"), basestring):
raise Exception
except:
print "Quirk malformed: %s" % (name)
msgbox = QtGui.QMessageBox()
msgbox.setWindowTitle("Error!")
msgbox.setText("Quirk malformed: %s" % (name))
msgbox.exec_()
else:
self.quirks[name] = CommandWrapper

View file

@ -323,7 +323,7 @@ class PesterQuirkTypes(QtGui.QDialog):
self.funclist2.setStyleSheet("color: #000000; background-color: #FFFFFF;")
from parsetools import quirkloader
funcs = [q+")" for q in quirkloader.quirks.keys()]
funcs = [q+"()" for q in quirkloader.quirks.keys()]
funcs.sort()
self.funclist.addItems(funcs)
self.funclist2.addItems(funcs)
@ -561,7 +561,7 @@ class PesterQuirkTypes(QtGui.QDialog):
def reloadQuirkFuncSlot(self):
from parsetools import reloadQuirkFunctions, quirkloader
reloadQuirkFunctions()
funcs = [q+")" for q in quirkloader.quirks.keys()]
funcs = [q+"()" for q in quirkloader.quirks.keys()]
funcs.sort()
self.funclist.clear()
self.funclist.addItems(funcs)
@ -1001,7 +1001,7 @@ class PesterOptions(QtGui.QDialog):
self.tabs = QtGui.QButtonGroup(self)
self.connect(self.tabs, QtCore.SIGNAL('buttonClicked(int)'),
self, QtCore.SLOT('changePage(int)'))
tabNames = ["Chum List", "Conversations", "Interface", "Sound", "Notifications", "Logging", "Idle/Updates", "Theme"]
tabNames = ["Chum List", "Conversations", "Interface", "Sound", "Notifications", "Logging", "Idle/Updates", "Theme", "Connection"]
if parent.advanced: tabNames.append("Advanced")
for t in tabNames:
button = QtGui.QPushButton(t)
@ -1020,6 +1020,24 @@ class PesterOptions(QtGui.QDialog):
font.setPointSize(8)
bandwidthLabel.setFont(font)
self.autonickserv = QtGui.QCheckBox("Auto-Identify with NickServ", self)
self.autonickserv.setChecked(parent.userprofile.getAutoIdentify())
self.connect(self.autonickserv, QtCore.SIGNAL('stateChanged(int)'),
self, QtCore.SLOT('autoNickServChange(int)'))
self.nickservpass = QtGui.QLineEdit(self)
self.nickservpass.setPlaceholderText("NickServ Password")
self.nickservpass.setEchoMode(QtGui.QLineEdit.PasswordEchoOnEdit)
self.nickservpass.setText(parent.userprofile.getNickServPass())
self.autojoinlist = QtGui.QListWidget(self)
self.autojoinlist.addItems(parent.userprofile.getAutoJoins())
self.addAutoJoinBtn = QtGui.QPushButton("Add", self)
self.connect(self.addAutoJoinBtn, QtCore.SIGNAL('clicked()'),
self, QtCore.SLOT('addAutoJoin()'))
self.delAutoJoinBtn = QtGui.QPushButton("Remove", self)
self.connect(self.delAutoJoinBtn, QtCore.SIGNAL('clicked()'),
self, QtCore.SLOT('delAutoJoin()'))
self.tabcheck = QtGui.QCheckBox("Tabbed Conversations", self)
if self.config.tabs():
self.tabcheck.setChecked(True)
@ -1259,8 +1277,6 @@ class PesterOptions(QtGui.QDialog):
layout_chumlist.addWidget(self.showemptycheck)
layout_chumlist.addWidget(self.showonlinenumbers)
layout_chumlist.addLayout(layout_3)
layout_chumlist.addWidget(self.bandwidthcheck)
layout_chumlist.addWidget(bandwidthLabel)
self.pages.addWidget(widget)
# Conversations
@ -1365,6 +1381,25 @@ class PesterOptions(QtGui.QDialog):
layout_theme.addWidget(self.ghostchum)
self.pages.addWidget(widget)
# Connection
widget = QtGui.QWidget()
layout_connect = QtGui.QVBoxLayout(widget)
layout_connect.setAlignment(QtCore.Qt.AlignTop)
layout_connect.addWidget(self.bandwidthcheck)
layout_connect.addWidget(bandwidthLabel)
layout_connect.addWidget(self.autonickserv)
layout_indent = QtGui.QVBoxLayout()
layout_indent.addWidget(self.nickservpass)
layout_indent.setContentsMargins(22,0,0,0)
layout_connect.addLayout(layout_indent)
layout_connect.addWidget(QtGui.QLabel("Auto-Join Memos:"))
layout_connect.addWidget(self.autojoinlist)
layout_8 = QtGui.QHBoxLayout()
layout_8.addWidget(self.addAutoJoinBtn)
layout_8.addWidget(self.delAutoJoinBtn)
layout_connect.addLayout(layout_8)
self.pages.addWidget(widget)
# Advanced
if parent.advanced:
widget = QtGui.QWidget()
@ -1411,6 +1446,32 @@ class PesterOptions(QtGui.QDialog):
self.notifyNewConvoCheck.setEnabled(True)
self.notifyMentionsCheck.setEnabled(True)
@QtCore.pyqtSlot(int)
def autoNickServChange(self, state):
self.nickservpass.setEnabled(state != 0)
@QtCore.pyqtSlot()
def addAutoJoin(self, mitem=None):
d = {"label": "Memo:", "inputname": "value" }
if mitem is not None:
d["value"] = str(mitem.text())
pdict = MultiTextDialog("ENTER MEMO", self, d).getText()
if pdict is None:
return
pdict["value"] = "#" + pdict["value"]
if mitem is None:
items = self.autojoinlist.findItems(pdict["value"], QtCore.Qt.MatchFixedString)
if len(items) == 0:
self.autojoinlist.addItem(pdict["value"])
else:
mitem.setText(pdict["value"])
@QtCore.pyqtSlot()
def delAutoJoin(self):
i = self.autojoinlist.currentRow()
if i >= 0:
self.autojoinlist.takeItem(i)
@QtCore.pyqtSlot(int)
def soundChange(self, state):
if state == 0:
@ -1588,6 +1649,7 @@ class PesterMemoList(QtGui.QDialog):
self.label = QtGui.QLabel("MEMOS")
self.channelarea = RightClickTree(self)
self.channelarea.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
self.channelarea.setStyleSheet(self.theme["main/chums/style"])
self.channelarea.optionsMenu = QtGui.QMenu(self)
self.channelarea.setColumnCount(2)
@ -1599,7 +1661,7 @@ class PesterMemoList(QtGui.QDialog):
self.channelarea.sortByColumn(0, QtCore.Qt.AscendingOrder)
self.connect(self.channelarea,
QtCore.SIGNAL('itemDoubleClicked(QTreeWidgetItem *, int)'),
self, QtCore.SLOT('joinActivatedMemo()'))
self, QtCore.SLOT('AcceptSelection()'))
self.orjoinlabel = QtGui.QLabel("OR MAKE A NEW MEMO:")
self.newmemo = QtGui.QLineEdit(channel, self)
@ -1616,7 +1678,7 @@ class PesterMemoList(QtGui.QDialog):
self.join = QtGui.QPushButton("JOIN", self)
self.join.setDefault(True)
self.connect(self.join, QtCore.SIGNAL('clicked()'),
self, QtCore.SLOT('checkEmpty()'))
self, QtCore.SLOT('AcceptIfSelectionMade()'))
layout_ok = QtGui.QHBoxLayout()
layout_ok.addWidget(self.cancel)
layout_ok.addWidget(self.join)
@ -1644,8 +1706,12 @@ class PesterMemoList(QtGui.QDialog):
def newmemoname(self):
return self.newmemo.text()
def selectedmemo(self):
return self.channelarea.currentItem()
def SelectedMemos(self):
return self.channelarea.selectedItems()
def HasSelection(self):
return len(self.SelectedMemos()) > 0 or self.newmemoname()
def updateChannels(self, channels):
for c in channels:
@ -1663,13 +1729,12 @@ class PesterMemoList(QtGui.QDialog):
item.setIcon(QtGui.QIcon(theme["memos/memoicon"]))
@QtCore.pyqtSlot()
def checkEmpty(self):
newmemo = self.newmemoname()
selectedmemo = self.selectedmemo()
if newmemo or selectedmemo:
self.accept()
def AcceptIfSelectionMade(self):
if self.HasSelection():
self.AcceptSelection()
@QtCore.pyqtSlot()
def joinActivatedMemo(self):
def AcceptSelection(self):
self.accept()

19
nickservmsgs.py Normal file
View file

@ -0,0 +1,19 @@
# Hardcoded messages that NickServ sends and what to display to the user instead
messages = {
"Your nick isn't registered.":
"", # display the same
"Password accepted - you are now recognized.":
"", # display the same
"If you do not change within one minute, I will change your nick.":
"You have 1 minute to identify.",
"If you do not change within 20 seconds, I will change your nick.":
"You have 20 seconds to identify."
}
def translate(msg):
if msg in messages:
if messages[msg] == "":
return msg
return messages[msg]
return None

View file

@ -6,7 +6,9 @@ from datetime import timedelta
from PyQt4 import QtGui
from generic import mysteryTime
from quirks import ScriptQuirks
from pyquirks import PythonQuirks
from luaquirks import LuaQuirks
_ctag_begin = re.compile(r'(?i)<c=(.*?)>')
_gtag_begin = re.compile(r'(?i)<g[a-f]>')
@ -23,12 +25,16 @@ _format_begin = re.compile(r'(?i)<([ibu])>')
_format_end = re.compile(r'(?i)</([ibu])>')
_honk = re.compile(r"(?i)\bhonk\b")
quirkloader = PythonQuirks()
quirkloader = ScriptQuirks()
quirkloader.add(PythonQuirks())
quirkloader.add(LuaQuirks())
quirkloader.loadAll()
print quirkloader.funcre()
_functionre = re.compile(r"%s" % quirkloader.funcre())
_groupre = re.compile(r"\\([0-9]+)")
def reloadQuirkFunctions():
quirkloader.load()
quirkloader.loadAll()
global _functionre
_functionre = re.compile(r"%s" % quirkloader.funcre())
@ -395,8 +401,8 @@ def parseRegexpFunctions(to):
backr = _groupre.search(mo.group())
if backr is not None:
current.append(backreference(backr.group(1)))
elif mo.group() in functiondict.keys():
p = parseLeaf(functiondict[mo.group()], current)
elif mo.group()[:-1] in functiondict.keys():
p = parseLeaf(functiondict[mo.group()[:-1]], current)
current.append(p)
current = p
elif mo.group() == ")":

View file

@ -40,7 +40,7 @@ else:
minor = int(vnum[vnum.find(".")+1:])
if not ((major > 4) or (major == 4 and minor >= 6)):
print "ERROR: Pesterchum requires Qt version >= 4.6"
print "You currently have version " + vnum + ". Please ungrade Qt"
print "You currently have version " + vnum + ". Please upgrade Qt"
exit()
import ostools
@ -89,7 +89,8 @@ from memos import PesterMemo, MemoTabWindow, TimeTracker
from irc import PesterIRC
from logviewer import PesterLogUserSelect, PesterLogViewer
from bugreport import BugReporter
from randomer import RandomHandler
from randomer import RandomHandler, RANDNICK
import nickservmsgs
# Rawr, fuck you OSX leopard
if not ostools.isOSXLeopard():
@ -103,6 +104,9 @@ canon_handles = ["apocalypseArisen", "arsenicCatnip", "arachnidsGrip", "adiosTor
"caligulasAquarium", "cuttlefishCuller", "carcinoGeneticist", "centaursTesticle", \
"grimAuxiliatrix", "gallowsCalibrator", "gardenGnostic", "ectoBiologist", \
"twinArmageddons", "terminallyCapricious", "turntechGodhead", "tentacleTherapist"]
CUSTOMBOTS = ["CALSPRITE", RANDNICK.upper()]
BOTNAMES = ["NICKSERV", "CHANSERV", "MEMOSERV", "OPERSERV", "HELPSERV"]
BOTNAMES.extend(CUSTOMBOTS)
class waitingMessageHolder(object):
@ -982,10 +986,12 @@ class TrollSlumWindow(QtGui.QFrame):
unblockChumSignal = QtCore.pyqtSignal(QtCore.QString)
class PesterWindow(MovingWindow):
def __init__(self, options, parent=None):
def __init__(self, options, parent=None, app=None):
MovingWindow.__init__(self, parent,
(QtCore.Qt.CustomizeWindowHint |
QtCore.Qt.FramelessWindowHint))
self.autoJoinDone = False
self.app = app
self.convos = CaseInsensitiveDict()
self.memos = CaseInsensitiveDict()
self.tabconvo = None
@ -1056,7 +1062,7 @@ class PesterWindow(MovingWindow):
exitaction = QtGui.QAction(self.theme["main/menus/client/exit"], self)
self.exitaction = exitaction
self.connect(exitaction, QtCore.SIGNAL('triggered()'),
self, QtCore.SLOT('close()'))
self.app, QtCore.SLOT('quit()'))
userlistaction = QtGui.QAction(self.theme["main/menus/client/userlist"], self)
self.userlistaction = userlistaction
self.connect(userlistaction, QtCore.SIGNAL('triggered()'),
@ -1305,8 +1311,9 @@ class PesterWindow(MovingWindow):
t.show()
elif not self.config.notifyOptions() & self.config.NEWCONVO:
if msg[:11] != "PESTERCHUM:":
t = self.tm.Toast("From: %s" % handle, re.sub("</?c(=.*?)?>", "", msg))
t.show()
if handle.upper() not in BOTNAMES:
t = self.tm.Toast("From: %s" % handle, re.sub("</?c(=.*?)?>", "", msg))
t.show()
else:
if msg == "PESTERCHUM:CEASE":
t = self.tm.Toast("Closed Conversation", handle)
@ -1355,19 +1362,25 @@ class PesterWindow(MovingWindow):
systemColor = QtGui.QColor(self.theme["memos/systemMsgColor"])
msg = "<c=%s>%s</c>" % (systemColor.name(), msg)
memo.addMessage(msg, handle)
mentioned = False
m = convertTags(msg, "text")
if m.find(":") <= 3:
m = m[m.find(":"):]
for search in self.userprofile.getMentions():
if re.search(search, m):
mentioned = True
break
if mentioned:
if self.config.notifyOptions() & self.config.INITIALS:
t = self.tm.Toast(chan, re.sub("</?c(=.*?)?>", "", msg))
t.show()
if self.config.soundOn():
if self.config.memoSound():
if self.config.nameSound():
m = convertTags(msg, "text")
if m.find(":") <= 3:
m = m[m.find(":"):]
for search in self.userprofile.getMentions():
if re.search(search, m):
if self.config.notifyOptions() & self.config.INITIALS:
t = self.tm.Toast(chan, re.sub("</?c(=.*?)?>", "", msg))
t.show()
self.namesound.play()
return
if mentioned:
self.namesound.play()
return
if self.honk and re.search(r"\bhonk\b", convertTags(msg, "text"), re.I):
self.honksound.play()
elif self.config.memoPing():
@ -1413,18 +1426,12 @@ class PesterWindow(MovingWindow):
self.connect(convoWindow, QtCore.SIGNAL('windowClosed(QString)'),
self, QtCore.SLOT('closeConvo(QString)'))
self.convos[chum.handle] = convoWindow
if unicode(chum.handle).upper() == "CHANSERV" or \
unicode(chum.handle).upper() == "NICKSERV" or \
unicode(chum.handle).upper() == "MEMOSERV" or \
unicode(chum.handle).upper() == "OPERSERV" or \
unicode(chum.handle).upper() == "HELPSERV":
if unicode(chum.handle).upper() in BOTNAMES:
convoWindow.toggleQuirks(True)
convoWindow.quirksOff.setChecked(True)
if unicode(chum.handle).upper() in CUSTOMBOTS:
self.newConvoStarted.emit(QtCore.QString(chum.handle), initiated)
else:
if unicode(chum.handle).upper() == "CALSPRITE" or \
unicode(chum.handle).upper() == "RANDOMENCOUNTER":
convoWindow.toggleQuirks(True)
convoWindow.quirksOff.setChecked(True)
self.newConvoStarted.emit(QtCore.QString(chum.handle), initiated)
convoWindow.show()
@ -1706,11 +1713,25 @@ class PesterWindow(MovingWindow):
else:
self.waitingMessages.answerMessage()
def doAutoIdentify(self):
if self.userprofile.getAutoIdentify():
self.sendMessage.emit("identify " + self.userprofile.getNickServPass(), "NickServ")
def doAutoJoins(self):
if not self.autoJoinDone:
self.autoJoinDone = True
for memo in self.userprofile.getAutoJoins():
self.newMemo(memo, "i")
@QtCore.pyqtSlot()
def connected(self):
if self.loadingscreen:
self.loadingscreen.done(QtGui.QDialog.Accepted)
self.loadingscreen = None
self.doAutoIdentify()
self.doAutoJoins()
@QtCore.pyqtSlot()
def blockSelectedChum(self):
curChumListing = self.chumList.currentItem()
@ -1803,6 +1824,11 @@ class PesterWindow(MovingWindow):
self.randhandler.incoming(msg)
elif self.convos.has_key(h):
self.newMessage(h, m)
elif h.upper() == "NICKSERV" and "PESTERCHUM:" not in m:
m = nickservmsgs.translate(m)
if m:
t = self.tm.Toast("NickServ:", m)
t.show()
@QtCore.pyqtSlot(QtCore.QString, QtCore.QString)
def deliverInvite(self, handle, channel):
msgbox = QtGui.QMessageBox()
@ -2058,18 +2084,21 @@ class PesterWindow(MovingWindow):
self.memochooser.show()
@QtCore.pyqtSlot()
def joinSelectedMemo(self):
newmemo = self.memochooser.newmemoname()
selectedmemo = self.memochooser.selectedmemo()
time = unicode(self.memochooser.timeinput.text())
secret = self.memochooser.secretChannel.isChecked()
invite = self.memochooser.inviteChannel.isChecked()
if newmemo:
if self.memochooser.newmemoname():
newmemo = self.memochooser.newmemoname()
channel = "#"+unicode(newmemo).replace(" ", "_")
channel = re.sub(r"[^A-Za-z0-9#_]", "", channel)
self.newMemo(channel, time, secret=secret, invite=invite)
elif selectedmemo:
channel = "#"+unicode(selectedmemo.target)
for SelectedMemo in self.memochooser.SelectedMemos():
channel = "#"+unicode(SelectedMemo.target)
self.newMemo(channel, time)
self.memochooser = None
@QtCore.pyqtSlot()
def memoChooserClose(self):
@ -2443,6 +2472,16 @@ class PesterWindow(MovingWindow):
self.leftChannel.emit("#pesterchum")
else:
self.joinChannel.emit("#pesterchum")
# nickserv
autoidentify = self.optionmenu.autonickserv.isChecked()
nickservpass = self.optionmenu.nickservpass.text()
self.userprofile.setAutoIdentify(autoidentify)
self.userprofile.setNickServPass(str(nickservpass))
# auto join memos
autojoins = []
for i in range(self.optionmenu.autojoinlist.count()):
autojoins.append(str(self.optionmenu.autojoinlist.item(i).text()))
self.userprofile.setAutoJoins(autojoins)
# advanced
## user mode
if self.advanced:
@ -2463,7 +2502,7 @@ class PesterWindow(MovingWindow):
self, QtCore.SLOT('closeToTray()'));
elif old == 2: # quit
self.disconnect(button, QtCore.SIGNAL('clicked()'),
self, QtCore.SLOT('close()'));
self.app, QtCore.SLOT('quit()'));
if setting == 0: # minimize to taskbar
self.connect(button, QtCore.SIGNAL('clicked()'),
@ -2473,7 +2512,7 @@ class PesterWindow(MovingWindow):
self, QtCore.SLOT('closeToTray()'));
elif setting == 2: # quit
self.connect(button, QtCore.SIGNAL('clicked()'),
self, QtCore.SLOT('close()'));
self.app, QtCore.SLOT('quit()'));
@QtCore.pyqtSlot()
def themeSelectOverride(self):
@ -2618,6 +2657,8 @@ class PesterWindow(MovingWindow):
@QtCore.pyqtSlot(QtCore.QString)
def myHandleChanged(self, handle):
if self.profile().handle == handle:
self.doAutoIdentify()
self.doAutoJoins()
return
else:
self.nickCollision(self.profile().handle, handle)
@ -2695,6 +2736,7 @@ class MainProgram(QtCore.QObject):
QtCore.QObject.__init__(self)
self.app = QtGui.QApplication(sys.argv)
self.app.setApplicationName("Pesterchum 3.14")
self.app.setQuitOnLastWindowClosed(False)
options = self.oppts(sys.argv[1:])
@ -2707,7 +2749,7 @@ class MainProgram(QtCore.QObject):
print "Warning: No sound! %s" % (e)
else:
print "Warning: No sound!"
self.widget = PesterWindow(options)
self.widget = PesterWindow(options, app=self.app)
self.widget.show()
self.trayicon = PesterTray(PesterIcon(self.widget.theme["main/icon"]), self.widget, self.app)
@ -2729,7 +2771,7 @@ class MainProgram(QtCore.QObject):
self.widget, QtCore.SLOT('showMinimized()'))
exitAction = QtGui.QAction("EXIT", self)
self.trayicon.connect(exitAction, QtCore.SIGNAL('triggered()'),
self.widget, QtCore.SLOT('close()'))
self.app, QtCore.SLOT('quit()'))
self.traymenu.addAction(miniAction)
self.traymenu.addAction(exitAction)
@ -2942,7 +2984,7 @@ Click this message to never see this again.")
widget.loadingscreen = LoadingScreen(widget)
widget.loadingscreen.loadinglabel.setText(msg)
self.connect(widget.loadingscreen, QtCore.SIGNAL('rejected()'),
widget, QtCore.SLOT('close()'))
widget.app, QtCore.SLOT('quit()'))
self.connect(self.widget.loadingscreen, QtCore.SIGNAL('tryAgain()'),
self, QtCore.SLOT('tryAgain()'))
if hasattr(self, 'irc') and self.irc.registeredIRC:

View file

@ -370,6 +370,7 @@ class userProfile(object):
self.mentions = [r"\b(%s)\b" % ("|".join(initials))]
else:
self.mentions = []
self.autojoins = []
else:
fp = open("%s/%s.js" % (self.profiledir, user))
self.userprofile = json.load(fp)
@ -394,6 +395,20 @@ class userProfile(object):
else:
self.userprofile["mentions"] = []
self.mentions = self.userprofile["mentions"]
if "autojoins" not in self.userprofile:
self.userprofile["autojoins"] = []
self.autojoins = self.userprofile["autojoins"]
try:
with open(_datadir+"passwd.js") as fp:
self.passwd = json.load(fp)
except Exception, e:
self.passwd = {}
self.autoidentify = False
self.nickservpass = ""
if self.chat.handle in self.passwd:
self.autoidentify = self.passwd[self.chat.handle]["auto"]
self.nickservpass = self.passwd[self.chat.handle]["pw"]
def setMood(self, mood):
self.chat.mood = mood
@ -435,6 +450,28 @@ class userProfile(object):
self.save()
def getTheme(self):
return self.theme
def getAutoIdentify(self):
return self.autoidentify
def setAutoIdentify(self, b):
self.autoidentify = b
if self.chat.handle not in self.passwd:
self.passwd[self.chat.handle] = {}
self.passwd[self.chat.handle]["auto"] = b
self.saveNickServPass()
def getNickServPass(self):
return self.nickservpass
def setNickServPass(self, pw):
self.nickservpass = pw
if self.chat.handle not in self.passwd:
self.passwd[self.chat.handle] = {}
self.passwd[self.chat.handle]["pw"] = pw
self.saveNickServPass()
def getAutoJoins(self):
return self.autojoins
def setAutoJoins(self, autojoins):
self.autojoins = autojoins
self.userprofile["autojoins"] = self.autojoins
self.save()
def save(self):
handle = self.chat.handle
if handle[0:12] == "pesterClient":
@ -447,6 +484,17 @@ class userProfile(object):
fp = open("%s/%s.js" % (self.profiledir, handle), 'w')
fp.write(jsonoutput)
fp.close()
def saveNickServPass(self):
# remove profiles with no passwords
for h,t in self.passwd.items():
if "auto" not in t or "pw" not in t or t["pw"] == "":
del self.passwd[h]
try:
jsonoutput = json.dumps(self.passwd, indent=4)
except ValueError, e:
raise e
with open(_datadir+"passwd.js", 'w') as fp:
fp.write(jsonoutput)
@staticmethod
def newUserProfile(chatprofile):
if os.path.exists("%s/%s.js" % (_datadir+"profiles", chatprofile.handle)):

View file

@ -1,57 +1,26 @@
import os, sys, imp, re, ostools
from quirks import ScriptQuirks
from PyQt4 import QtGui, QtCore
class PythonQuirks(object):
def __init__(self):
self._datadir = ostools.getDataDir()
self.home = os.getcwd()
self.quirks = {}
self.last = {}
self.load()
class PythonQuirks(ScriptQuirks):
def loadModule(self, name, filename):
return imp.load_source(name, filename)
def load(self):
self.last = self.quirks.copy()
self.quirks.clear()
filenames = []
if not os.path.exists(os.path.join(self.home, 'quirks')):
os.mkdir(os.path.join(self.home, 'quirks'))
for fn in os.listdir(os.path.join(self.home, 'quirks')):
if fn.endswith('.py') and not fn.startswith('_'):
filenames.append(os.path.join(self.home, 'quirks', fn))
if self._datadir:
if not os.path.exists(os.path.join(self._datadir, 'quirks')):
os.mkdir(os.path.join(self._datadir, 'quirks'))
for fn in os.listdir(os.path.join(self._datadir, 'quirks')):
if fn.endswith('.py') and not fn.startswith('_'):
filenames.append(os.path.join(self._datadir, 'quirks', fn))
def getExtension(self):
return '.py'
modules = []
for filename in filenames:
name = os.path.basename(filename)[:-3]
try: module = imp.load_source(name, filename)
except Exception, e:
print "Error loading %s: %s (in pyquirks.py)" % (name, e)
msgbox = QtGui.QMessageBox()
msgbox.setWindowTitle("Error!")
msgbox.setText("Error loading %s: %s (in pyquirks.py)" % (name, e))
msgbox.exec_()
else:
if hasattr(module, 'setup'):
module.setup()
self.register(vars(module))
modules.append(name)
for k in self.last:
if k in self.quirks:
if self.last[k] == self.quirks[k]:
del self.quirks[k]
def modHas(self, module, attr):
if attr == 'commands':
variables = vars(module)
for name, obj in variables.iteritems():
if self.modHas(obj, 'command'):
return True
return hasattr(module, attr)
if self.quirks:
print 'Registered quirks:', '), '.join(self.quirks) + ")"
else:print "Warning: Couldn't find any python quirks"
def register(self, variables):
def register(self, module):
variables = vars(module)
for name, obj in variables.iteritems():
if hasattr(obj, 'command'):
if self.modHas(obj, 'command'):
try:
if not isinstance(obj("test"), basestring):
raise Exception
@ -62,13 +31,5 @@ class PythonQuirks(object):
msgbox.setText("Quirk malformed: %s" % (obj.command))
msgbox.exec_()
else:
self.quirks[obj.command+"("] = obj
self.quirks[obj.command] = obj
def funcre(self):
if not self.quirks:
return r"\\[0-9]+"
f = r"("
for q in self.quirks:
f = f + q[:-1]+r"\(|"
f = f + r"\)|\\[0-9]+)"
return f

91
quirks.py Normal file
View file

@ -0,0 +1,91 @@
import os, sys, re, ostools
from PyQt4 import QtGui, QtCore
class ScriptQuirks(object):
def __init__(self):
self._datadir = ostools.getDataDir()
self.home = os.getcwd()
self.quirks = {}
self.last = {}
self.scripts = []
#self.load()
def loadModule(self, name, filename):
raise Exception
def modHas(self, module, attr):
return False
def loadAll(self):
self.last = self.quirks.copy()
self.quirks.clear()
for script in self.scripts:
print script.getExtension()
script.load()
#print script.quirks
for q in script.quirks:
self.quirks.update(script.quirks)
for k in self.last:
if k in self.quirks:
if self.last[k] == self.quirks[k]:
del self.quirks[k]
#print self.quirks
if self.quirks:
print 'Registered quirks:', '(), '.join(self.quirks) + "()"
else:
print "Warning: Couldn't find any script quirks"
def add(self, script):
self.scripts.append(script)
def load(self):
self.last = self.quirks.copy()
self.quirks.clear()
extension = self.getExtension()
filenames = []
if not os.path.exists(os.path.join(self.home, 'quirks')):
os.mkdir(os.path.join(self.home, 'quirks'))
for fn in os.listdir(os.path.join(self.home, 'quirks')):
if fn.endswith(extension) and not fn.startswith('_'):
filenames.append(os.path.join(self.home, 'quirks', fn))
if self._datadir:
if not os.path.exists(os.path.join(self._datadir, 'quirks')):
os.mkdir(os.path.join(self._datadir, 'quirks'))
for fn in os.listdir(os.path.join(self._datadir, 'quirks')):
if fn.endswith(extension) and not fn.startswith('_'):
filenames.append(os.path.join(self._datadir, 'quirks', fn))
modules = []
for filename in filenames:
extension_length = len(self.getExtension())
name = os.path.basename(filename)[:-extension_length]
try:
module = self.loadModule(name, filename)
if module is None:
continue
except Exception, e:
print "Error loading %s: %s (in quirks.py)" % (os.path.basename(name), e)
msgbox = QtGui.QMessageBox()
msgbox.setWindowTitle("Error!")
msgbox.setText("Error loading %s: %s (in quirks.py)" % (os.path.basename(filename), e))
msgbox.exec_()
else:
if self.modHas(module, 'setup'):
module.setup()
if self.modHas(module, 'commands'):
self.register(module)
modules.append(name)
for k in self.last:
if k in self.quirks:
if self.last[k] == self.quirks[k]:
del self.quirks[k]
def funcre(self):
if not self.quirks:
return r"\\[0-9]+"
f = r"("
for q in self.quirks:
f = f + q+r"\(|"
f = f + r"\)|\\[0-9]+)"
return f

18
quirks/example.lua Normal file
View file

@ -0,0 +1,18 @@
module(..., package.seeall)
commands = {}
local function upper(text)
return string.upper(text)
end
commands.luaupper = upper
local function lower(text)
return string.lower(text)
end
commands.lualower = lower
local function utf8reverse(text)
return text:gsub("([\194-\244][\128-\191]+)", string.reverse):reverse()
end
commands.luareverse = utf8reverse

View file

@ -1,9 +1,11 @@
from PyQt4 import QtGui, QtCore
RANDNICK = "randomEncounter"
class RandomHandler(QtCore.QObject):
def __init__(self, parent):
QtCore.QObject.__init__(self, parent)
self.randNick = "randomEncounter"
self.randNick = RANDNICK
self.mainwindow = parent
self.queue = []
self.running = False

View file

@ -74,7 +74,11 @@ class ToastMachine(object):
t = None
for (k,v) in self.machine.types.iteritems():
if self.machine.type == k:
args = inspect.getargspec(v.__init__).args
try:
args = inspect.getargspec(v.__init__).args
except:
args = []
extras = {}
if 'parent' in args:
extras['parent'] = self.machine.parent