commit
f2a482b241
15 changed files with 441 additions and 114 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,3 +1,5 @@
|
|||
*.swp
|
||||
*~
|
||||
logs/*
|
||||
build/*
|
||||
profiles/*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
3
irc.py
|
@ -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
61
luaquirks.py
Normal 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
|
||||
|
95
menus.py
95
menus.py
|
@ -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
19
nickservmsgs.py
Normal 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
|
|
@ -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() == ")":
|
||||
|
|
|
@ -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,6 +1311,7 @@ class PesterWindow(MovingWindow):
|
|||
t.show()
|
||||
elif not self.config.notifyOptions() & self.config.NEWCONVO:
|
||||
if msg[:11] != "PESTERCHUM:":
|
||||
if handle.upper() not in BOTNAMES:
|
||||
t = self.tm.Toast("From: %s" % handle, re.sub("</?c(=.*?)?>", "", msg))
|
||||
t.show()
|
||||
else:
|
||||
|
@ -1355,17 +1362,23 @@ class PesterWindow(MovingWindow):
|
|||
systemColor = QtGui.QColor(self.theme["memos/systemMsgColor"])
|
||||
msg = "<c=%s>%s</c>" % (systemColor.name(), msg)
|
||||
memo.addMessage(msg, handle)
|
||||
if self.config.soundOn():
|
||||
if self.config.memoSound():
|
||||
if self.config.nameSound():
|
||||
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():
|
||||
if mentioned:
|
||||
self.namesound.play()
|
||||
return
|
||||
if self.honk and re.search(r"\bhonk\b", convertTags(msg, "text"), re.I):
|
||||
|
@ -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:
|
||||
|
|
48
profile.py
48
profile.py
|
@ -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)):
|
||||
|
|
75
pyquirks.py
75
pyquirks.py
|
@ -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]
|
||||
|
||||
if self.quirks:
|
||||
print 'Registered quirks:', '), '.join(self.quirks) + ")"
|
||||
else:print "Warning: Couldn't find any python quirks"
|
||||
|
||||
def register(self, variables):
|
||||
def modHas(self, module, attr):
|
||||
if attr == 'commands':
|
||||
variables = vars(module)
|
||||
for name, obj in variables.iteritems():
|
||||
if hasattr(obj, 'command'):
|
||||
if self.modHas(obj, 'command'):
|
||||
return True
|
||||
return hasattr(module, attr)
|
||||
|
||||
def register(self, module):
|
||||
variables = vars(module)
|
||||
for name, obj in variables.iteritems():
|
||||
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
91
quirks.py
Normal 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
18
quirks/example.lua
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
4
toast.py
4
toast.py
|
@ -74,7 +74,11 @@ class ToastMachine(object):
|
|||
t = None
|
||||
for (k,v) in self.machine.types.iteritems():
|
||||
if self.machine.type == k:
|
||||
try:
|
||||
args = inspect.getargspec(v.__init__).args
|
||||
except:
|
||||
args = []
|
||||
|
||||
extras = {}
|
||||
if 'parent' in args:
|
||||
extras['parent'] = self.machine.parent
|
||||
|
|
Loading…
Reference in a new issue