132 pix2 = UI.PixmapCache.getPixmap("ircAway.png") |
132 pix2 = UI.PixmapCache.getPixmap("ircAway.png") |
133 painter = QPainter(pix1) |
133 painter = QPainter(pix1) |
134 painter.drawPixmap(0, 0, pix2) |
134 painter.drawPixmap(0, 0, pix2) |
135 painter.end() |
135 painter.end() |
136 return QIcon(pix1) |
136 return QIcon(pix1) |
|
137 |
|
138 def parseWhoFlags(self, flags): |
|
139 """ |
|
140 Public method to parse the user flags reported by a WHO command. |
|
141 |
|
142 @param flags user flags as reported by WHO (string) |
|
143 """ |
|
144 # H The user is not away. |
|
145 # G The user is set away. |
|
146 # * The user is an IRC operator. |
|
147 # @ The user is a channel op in the channel listed in the first field. |
|
148 # + The user is voiced in the channel listed. |
|
149 if flags.endswith("@"): |
|
150 privilege = IrcUserItem.Operator |
|
151 elif flags.endswith("+"): |
|
152 privilege = IrcUserItem.Voice |
|
153 else: |
|
154 privilege = IrcUserItem.Normal |
|
155 if "*" in flags: |
|
156 privilege = IrcUserItem.Admin |
|
157 if flags.startswith("G"): |
|
158 privilege |= IrcUserItem.Away |
|
159 self.__privilege = privilege |
|
160 self.__setIcon() |
137 |
161 |
138 |
162 |
139 class IrcChannelWidget(QWidget, Ui_IrcChannelWidget): |
163 class IrcChannelWidget(QWidget, Ui_IrcChannelWidget): |
140 """ |
164 """ |
141 Class implementing the IRC channel widget. |
165 Class implementing the IRC channel widget. |
192 |
205 |
193 self.__patterns = [ |
206 self.__patterns = [ |
194 # :foo_!n=foo@foohost.bar.net PRIVMSG #eric-ide :some long message |
207 # :foo_!n=foo@foohost.bar.net PRIVMSG #eric-ide :some long message |
195 (re.compile(r":([^!]+).*\sPRIVMSG\s([^ ]+)\s:(.*)"), self.__message), |
208 (re.compile(r":([^!]+).*\sPRIVMSG\s([^ ]+)\s:(.*)"), self.__message), |
196 # :foo_!n=foo@foohost.bar.net JOIN :#eric-ide |
209 # :foo_!n=foo@foohost.bar.net JOIN :#eric-ide |
197 # :detlev_!~detlev@mnch-5d876cfa.pool.mediaWays.net JOIN #eric-ide |
|
198 (re.compile(r":([^!]+)!([^ ]+)\sJOIN\s:?([^ ]+)"), self.__userJoin), |
210 (re.compile(r":([^!]+)!([^ ]+)\sJOIN\s:?([^ ]+)"), self.__userJoin), |
199 # :foo_!n=foo@foohost.bar.net PART #eric-ide :part message |
211 # :foo_!n=foo@foohost.bar.net PART #eric-ide :part message |
200 (re.compile(r":([^!]+).*\sPART\s([^ ]+)\s:(.*)"), self.__userPart), |
212 (re.compile(r":([^!]+).*\sPART\s([^ ]+)\s:(.*)"), self.__userPart), |
201 # :foo_!n=foo@foohost.bar.net PART #eric-ide |
213 # :foo_!n=foo@foohost.bar.net PART #eric-ide |
202 (re.compile(r":([^!]+).*\sPART\s([^ ]+)\s*"), self.__userPart), |
214 (re.compile(r":([^!]+).*\sPART\s([^ ]+)\s*"), self.__userPart), |
204 (re.compile(r":([^!]+).*\sQUIT\s:(.*)"), self.__userQuit), |
216 (re.compile(r":([^!]+).*\sQUIT\s:(.*)"), self.__userQuit), |
205 # :foo_!n=foo@foohost.bar.net QUIT |
217 # :foo_!n=foo@foohost.bar.net QUIT |
206 (re.compile(r":([^!]+).*\sQUIT\s*"), self.__userQuit), |
218 (re.compile(r":([^!]+).*\sQUIT\s*"), self.__userQuit), |
207 # :foo_!n=foo@foohost.bar.net NICK :newnick |
219 # :foo_!n=foo@foohost.bar.net NICK :newnick |
208 (re.compile(r":([^!]+).*\sNICK\s:(.*)"), self.__userNickChange), |
220 (re.compile(r":([^!]+).*\sNICK\s:(.*)"), self.__userNickChange), |
209 # :barty!n=foo@foohost.bar.net MODE #eric-ide +o foo_ |
221 # :foo_!n=foo@foohost.bar.net MODE #eric-ide +o foo_ |
210 (re.compile(r":([^!]+).*\sMODE\s([^ ]+)\s([^ ]+)\s([^ ]+).*"), |
222 (re.compile(r":([^!]+).*\sMODE\s([^ ]+)\s([+-][ovO]+)\s([^ ]+).*"), |
211 self.__setUserPrivilege), |
223 self.__setUserPrivilege), |
|
224 # :cameron.freenode.net MODE #testeric +ns |
|
225 (re.compile(r":([^ ]+)\sMODE\s([^ ]+)\s(.+)"), self.__updateChannelModes), |
212 # :sturgeon.freenode.net 301 foo_ bar :Gone away for now |
226 # :sturgeon.freenode.net 301 foo_ bar :Gone away for now |
213 (re.compile(r":.*\s301\s([^ ]+)\s([^ ]+)\s:(.+)"), self.__userAway), |
227 (re.compile(r":.*\s301\s([^ ]+)\s([^ ]+)\s:(.+)"), self.__userAway), |
|
228 # :sturgeon.freenode.net 315 foo_ #eric-ide :End of /WHO list. |
|
229 (re.compile(r":.*\s315\s[^ ]+\s([^ ]+)\s:(.*)"), self.__whoEnd), |
214 # :zelazny.freenode.net 324 foo_ #eric-ide +cnt |
230 # :zelazny.freenode.net 324 foo_ #eric-ide +cnt |
215 (re.compile(r":.*\s324\s.*\s([^ ]+)\s(.+)"), self.__channelModes), |
231 (re.compile(r":.*\s324\s.*\s([^ ]+)\s(.+)"), self.__channelModes), |
216 # :zelazny.freenode.net 328 foo_ #eric-ide :http://www.buggeroff.com/ |
232 # :zelazny.freenode.net 328 foo_ #eric-ide :http://www.buggeroff.com/ |
217 (re.compile(r":.*\s328\s.*\s([^ ]+)\s:(.+)"), self.__channelUrl), |
233 (re.compile(r":.*\s328\s.*\s([^ ]+)\s:(.+)"), self.__channelUrl), |
218 # :zelazny.freenode.net 329 foo_ #eric-ide 1353001005 |
234 # :zelazny.freenode.net 329 foo_ #eric-ide 1353001005 |
219 (re.compile(r":.*\s329\s.*\s([^ ]+)\s(.+)"), self.__channelCreated), |
235 (re.compile(r":.*\s329\s.*\s([^ ]+)\s(.+)"), self.__channelCreated), |
220 # :zelazny.freenode.net 332 foo_ #eric-ide :eric support channel |
236 # :zelazny.freenode.net 332 foo_ #eric-ide :eric support channel |
221 (re.compile(r":.*\s332\s.*\s([^ ]+)\s:(.*)"), self.__setTopic), |
237 (re.compile(r":.*\s332\s.*\s([^ ]+)\s:(.*)"), self.__setTopic), |
222 # :zelazny.freenode.net foo_ 333 #eric-ide foo 1353089020 |
238 # :zelazny.freenode.net foo_ 333 #eric-ide foo 1353089020 |
223 (re.compile(r":.*\s333\s.*\s([^ ]+)\s([^ ]+)\s(\d+)"), self.__topicCreated), |
239 (re.compile(r":.*\s333\s.*\s([^ ]+)\s([^ ]+)\s(\d+)"), self.__topicCreated), |
|
240 # :cameron.freenode.net 352 detlev_ #eric-ide ~foo foohost.bar.net cameron.freenode.net foo_ H :0 Foo Bar |
|
241 (re.compile(r":.*\s352\s[^ ]+\s([^ ]+)\s([^ ]+)\s([^ ]+)\s[^ ]+\s([^ ]+)" |
|
242 r"\s([^ ]+)\s:\d+\s(.*)"), self.__whoEntry), |
224 # :zelazny.freenode.net 353 foo_ @ #eric-ide :@user1 +user2 user3 |
243 # :zelazny.freenode.net 353 foo_ @ #eric-ide :@user1 +user2 user3 |
225 (re.compile(r":.*\s353\s.*\s.\s([^ ]+)\s:(.*)"), self.__userList), |
244 (re.compile(r":.*\s353\s.*\s.\s([^ ]+)\s:(.*)"), self.__userList), |
|
245 # :sturgeon.freenode.net 354 foo_ 42 ChanServ H@ |
|
246 (re.compile(r":.*\s354\s[^ ]+\s42\s([^ ]+)\s(.*)"), self.__autoWhoEntry), |
226 # :zelazny.freenode.net 366 foo_ #eric-ide :End of /NAMES list. |
247 # :zelazny.freenode.net 366 foo_ #eric-ide :End of /NAMES list. |
227 (re.compile(r":.*\s366\s.*\s([^ ]+)\s:(.*)"), self.__ignore), |
248 (re.compile(r":.*\s366\s.*\s([^ ]+)\s:(.*)"), self.__ignore), |
228 # :sturgeon.freenode.net 704 foo_ index :Help topics available to users: |
249 # :sturgeon.freenode.net 704 foo_ index :Help topics available to users: |
229 (re.compile(r":.*\s70[456]\s[^ ]+\s([^ ]+)\s:(.*)"), self.__help), |
250 (re.compile(r":.*\s70[456]\s[^ ]+\s([^ ]+)\s:(.*)"), self.__help), |
230 ] |
251 ] |
|
252 |
|
253 self.__autoWhoTemplate = "WHO {0} %tnf,42" |
|
254 self.__autoWhoTimer = QTimer() |
|
255 self.__autoWhoTimer.setSingleShot(True) |
|
256 self.__autoWhoTimer.timeout.connect(self.__sendAutoWhoCommand) |
|
257 self.__autoWhoRequested = False |
231 |
258 |
232 @pyqtSlot() |
259 @pyqtSlot() |
233 def on_messageEdit_returnPressed(self): |
260 def on_messageEdit_returnPressed(self): |
234 """ |
261 """ |
235 Private slot to send a message to the channel. |
262 Private slot to send a message to the channel. |
627 .toString("yyyy-MM-dd hh:mm"))) |
655 .toString("yyyy-MM-dd hh:mm"))) |
628 return True |
656 return True |
629 |
657 |
630 return False |
658 return False |
631 |
659 |
|
660 def __updateChannelModes(self, match): |
|
661 """ |
|
662 Private method to handle a message reporting the channel modes. |
|
663 |
|
664 @param match match object that matched the pattern |
|
665 @return flag indicating whether the message was handled (boolean) |
|
666 """ |
|
667 # group(1) user or server |
|
668 # group(2) channel |
|
669 # group(3) modes and parameter list |
|
670 if match.group(2).lower() == self.__name: |
|
671 nick = match.group(1) |
|
672 modesParameters = match.group(3).split() |
|
673 modeString = modesParameters.pop(0) |
|
674 isPlus = True |
|
675 message = "" |
|
676 for mode in modeString: |
|
677 if mode == "+": |
|
678 isPlus = True |
|
679 continue |
|
680 elif mode == "-": |
|
681 isPlus = False |
|
682 continue |
|
683 elif mode == "a": |
|
684 if isPlus: |
|
685 message = self.trUtf8( |
|
686 "{0} sets the channel mode to 'anonymous'.").format(nick) |
|
687 else: |
|
688 message = self.trUtf8( |
|
689 "{0} removes the 'anonymous' mode from the channel.").format( |
|
690 nick) |
|
691 elif mode == "b": |
|
692 if isPlus: |
|
693 message = self.trUtf8( |
|
694 "{0} sets a ban on {1}.").format( |
|
695 nick, modesParameters.pop(0)) |
|
696 else: |
|
697 message = self.trUtf8( |
|
698 "{0} removes the ban on {1}.").format( |
|
699 nick, modesParameters.pop(0)) |
|
700 elif mode == "c": |
|
701 if isPlus: |
|
702 message = self.trUtf8( |
|
703 "{0} sets the channel mode to 'no colors allowed'.").format( |
|
704 nick) |
|
705 else: |
|
706 message = self.trUtf8( |
|
707 "{0} sets the channel mode to 'allow color codes'.").format( |
|
708 nick) |
|
709 elif mode == "e": |
|
710 if isPlus: |
|
711 message = self.trUtf8( |
|
712 "{0} sets a ban exception on {1}.").format( |
|
713 nick, modesParameters.pop(0)) |
|
714 else: |
|
715 message = self.trUtf8( |
|
716 "{0} removes the ban exception on {1}.").format( |
|
717 nick, modesParameters.pop(0)) |
|
718 elif mode == "i": |
|
719 if isPlus: |
|
720 message = self.trUtf8( |
|
721 "{0} sets the channel mode to 'invite only'.").format(nick) |
|
722 else: |
|
723 message = self.trUtf8( |
|
724 "{0} removes the 'invite only' mode from the channel." |
|
725 ).format(nick) |
|
726 elif mode == "k": |
|
727 if isPlus: |
|
728 message = self.trUtf8( |
|
729 "{0} sets the channel key to '{1}'.").format( |
|
730 nick, modesParameters.pop(0)) |
|
731 else: |
|
732 message = self.trUtf8( |
|
733 "{0} removes the channel key.").format(nick) |
|
734 elif mode == "l": |
|
735 if isPlus: |
|
736 message = self.trUtf8( |
|
737 "{0} sets the channel limit to %n nick(s).", "", |
|
738 int(modesParameters.pop(0))).format(nick) |
|
739 else: |
|
740 message = self.trUtf8( |
|
741 "{0} removes the channel limit.").format(nick) |
|
742 elif mode == "m": |
|
743 if isPlus: |
|
744 message = self.trUtf8( |
|
745 "{0} sets the channel mode to 'moderated'.").format(nick) |
|
746 else: |
|
747 message = self.trUtf8( |
|
748 "{0} sets the channel mode to 'unmoderated'.").format(nick) |
|
749 elif mode == "n": |
|
750 if isPlus: |
|
751 message = self.trUtf8( |
|
752 "{0} sets the channel mode to 'no messages from outside'." |
|
753 ).format(nick) |
|
754 else: |
|
755 message = self.trUtf8( |
|
756 "{0} sets the channel mode to 'allow messages from outside'." |
|
757 ).format(nick) |
|
758 elif mode == "p": |
|
759 if isPlus: |
|
760 message = self.trUtf8( |
|
761 "{0} sets the channel mode to 'private'.").format(nick) |
|
762 else: |
|
763 message = self.trUtf8( |
|
764 "{0} sets the channel mode to 'public'.").format(nick) |
|
765 elif mode == "q": |
|
766 if isPlus: |
|
767 message = self.trUtf8( |
|
768 "{0} sets the channel mode to 'quiet'.").format(nick) |
|
769 else: |
|
770 message = self.trUtf8( |
|
771 "{0} removes the 'quiet' mode from the channel.").format( |
|
772 nick) |
|
773 elif mode == "r": |
|
774 continue |
|
775 elif mode == "s": |
|
776 if isPlus: |
|
777 message = self.trUtf8( |
|
778 "{0} sets the channel mode to 'secret'.").format(nick) |
|
779 else: |
|
780 message = self.trUtf8( |
|
781 "{0} sets the channel mode to 'visible'.").format(nick) |
|
782 elif mode == "t": |
|
783 if isPlus: |
|
784 message = self.trUtf8( |
|
785 "{0} switches on 'topic protection'.").format(nick) |
|
786 else: |
|
787 message = self.trUtf8( |
|
788 "{0} switches off 'topic protection'.").format(nick) |
|
789 elif mode == "I": |
|
790 if isPlus: |
|
791 message = self.trUtf8( |
|
792 "{0} sets invitation mask {1}.").format( |
|
793 nick, modesParameters.pop(0)) |
|
794 else: |
|
795 message = self.trUtf8( |
|
796 "{0} removes the invitation mask {1}.").format( |
|
797 nick, modesParameters.pop(0)) |
|
798 |
|
799 self.__addManagementMessage(self.trUtf8("Mode"), message) |
|
800 |
|
801 return True |
|
802 |
|
803 return False |
|
804 |
632 def __setUserPrivilege(self, match): |
805 def __setUserPrivilege(self, match): |
633 """ |
806 """ |
634 Private method to handle a change of user privileges for the channel. |
807 Private method to handle a change of user privileges for the channel. |
635 |
808 |
636 @param match match object that matched the pattern |
809 @param match match object that matched the pattern |
968 Protected method handling show events. |
1141 Protected method handling show events. |
969 |
1142 |
970 @param evt reference to the show event (QShowEvent) |
1143 @param evt reference to the show event (QShowEvent) |
971 """ |
1144 """ |
972 self.__hidden = False |
1145 self.__hidden = False |
|
1146 |
|
1147 def initAutoWho(self): |
|
1148 """ |
|
1149 Public method to initialize the Auto Who system. |
|
1150 """ |
|
1151 if Preferences.getIrc("AutoUserInfoLookup"): |
|
1152 self.__autoWhoTimer.setInterval( |
|
1153 Preferences.getIrc("AutoUserInfoInterval") * 1000) |
|
1154 self.__autoWhoTimer.start() |
|
1155 |
|
1156 @pyqtSlot() |
|
1157 def __sendAutoWhoCommand(self): |
|
1158 """ |
|
1159 Private slot to send the WHO command to update the users list. |
|
1160 """ |
|
1161 if self.usersList.count() <= Preferences.getIrc("AutoUserInfoMax"): |
|
1162 self.__autoWhoRequested = True |
|
1163 self.sendData.emit(self.__autoWhoTemplate.format(self.__name)) |
|
1164 |
|
1165 def __autoWhoEntry(self, match): |
|
1166 """ |
|
1167 Private method to handle a WHO entry returned by the server as requested |
|
1168 automatically. |
|
1169 |
|
1170 @param match match object that matched the pattern |
|
1171 @return flag indicating whether the message was handled (boolean) |
|
1172 """ |
|
1173 # group(1) nick |
|
1174 # group(2) user flags |
|
1175 if self.__autoWhoRequested: |
|
1176 itm = self.__findUser(match.group(1)) |
|
1177 if itm: |
|
1178 itm.parseWhoFlags(match.group(2)) |
|
1179 return True |
|
1180 |
|
1181 return False |
|
1182 |
|
1183 def __whoEnd(self, match): |
|
1184 """ |
|
1185 Private method to handle the end of the WHO list. |
|
1186 |
|
1187 @param match match object that matched the pattern |
|
1188 @return flag indicating whether the message was handled (boolean) |
|
1189 """ |
|
1190 if match.group(1).lower() == self.__name: |
|
1191 if self.__autoWhoRequested: |
|
1192 self.__autoWhoRequested = False |
|
1193 self.initAutoWho() |
|
1194 else: |
|
1195 self.__addManagementMessage(self.trUtf8("Who"), |
|
1196 self.trUtf8("End of /WHO list for {0}.").format(match.group(1))) |
|
1197 return True |
|
1198 |
|
1199 return False |
|
1200 |
|
1201 def __whoEntry(self, match): |
|
1202 """ |
|
1203 Private method to handle a WHO entry returned by the server as requested |
|
1204 manually. |
|
1205 |
|
1206 @param match match object that matched the pattern |
|
1207 @return flag indicating whether the message was handled (boolean) |
|
1208 """ |
|
1209 # group(1) channel |
|
1210 # group(2) user |
|
1211 # group(3) host |
|
1212 # group(4) nick |
|
1213 # group(5) user flags |
|
1214 # group(6) real name |
|
1215 if match.group(2).lower() == self.__name: |
|
1216 away = self.trUtf8(" (Away)") if match.group(5).startswith("G") else "" |
|
1217 self.__addManagementMessage(self.trUtf8("Who"), |
|
1218 self.trUtf8("{0} is {1}@{2} ({3}){4}").format( |
|
1219 match.group(4), match.group(2), match.group(3), match.group(6), away)) |
|
1220 return True |
|
1221 |
|
1222 return False |
|
1223 |