37 |
35 |
38 |
36 |
39 class IrcWidget(QWidget, Ui_IrcWidget): |
37 class IrcWidget(QWidget, Ui_IrcWidget): |
40 """ |
38 """ |
41 Class implementing the IRC window. |
39 Class implementing the IRC window. |
42 |
40 |
43 @signal autoConnected() emitted after an automatic connection was initiated |
41 @signal autoConnected() emitted after an automatic connection was initiated |
44 """ |
42 """ |
|
43 |
45 autoConnected = pyqtSignal() |
44 autoConnected = pyqtSignal() |
46 |
45 |
47 ServerDisconnected = 1 |
46 ServerDisconnected = 1 |
48 ServerConnected = 2 |
47 ServerConnected = 2 |
49 ServerConnecting = 3 |
48 ServerConnecting = 3 |
50 |
49 |
51 def __init__(self, parent=None): |
50 def __init__(self, parent=None): |
52 """ |
51 """ |
53 Constructor |
52 Constructor |
54 |
53 |
55 @param parent reference to the parent widget (QWidget) |
54 @param parent reference to the parent widget (QWidget) |
56 """ |
55 """ |
57 super().__init__(parent) |
56 super().__init__(parent) |
58 self.setupUi(self) |
57 self.setupUi(self) |
59 |
58 |
60 from .IrcNetworkManager import IrcNetworkManager |
59 from .IrcNetworkManager import IrcNetworkManager |
|
60 |
61 self.__ircNetworkManager = IrcNetworkManager(self) |
61 self.__ircNetworkManager = IrcNetworkManager(self) |
62 |
62 |
63 self.__leaveButton = QToolButton(self) |
63 self.__leaveButton = QToolButton(self) |
64 self.__leaveButton.setIcon( |
64 self.__leaveButton.setIcon(UI.PixmapCache.getIcon("ircCloseChannel")) |
65 UI.PixmapCache.getIcon("ircCloseChannel")) |
65 self.__leaveButton.setToolTip(self.tr("Press to leave the current channel")) |
66 self.__leaveButton.setToolTip( |
|
67 self.tr("Press to leave the current channel")) |
|
68 self.__leaveButton.clicked.connect(self.__leaveChannel) |
66 self.__leaveButton.clicked.connect(self.__leaveChannel) |
69 self.__leaveButton.setEnabled(False) |
67 self.__leaveButton.setEnabled(False) |
70 self.channelsWidget.setCornerWidget( |
68 self.channelsWidget.setCornerWidget( |
71 self.__leaveButton, Qt.Corner.BottomRightCorner) |
69 self.__leaveButton, Qt.Corner.BottomRightCorner |
|
70 ) |
72 self.channelsWidget.setTabsClosable(False) |
71 self.channelsWidget.setTabsClosable(False) |
73 if not isMacPlatform(): |
72 if not isMacPlatform(): |
74 self.channelsWidget.setTabPosition(QTabWidget.TabPosition.South) |
73 self.channelsWidget.setTabPosition(QTabWidget.TabPosition.South) |
75 |
74 |
76 height = self.height() |
75 height = self.height() |
77 self.splitter.setSizes([int(height * 0.6), int(height * 0.4)]) |
76 self.splitter.setSizes([int(height * 0.6), int(height * 0.4)]) |
78 |
77 |
79 self.__channelList = [] |
78 self.__channelList = [] |
80 self.__channelTypePrefixes = "" |
79 self.__channelTypePrefixes = "" |
81 self.__userName = "" |
80 self.__userName = "" |
82 self.__identityName = "" |
81 self.__identityName = "" |
83 self.__quitMessage = "" |
82 self.__quitMessage = "" |
84 self.__nickIndex = -1 |
83 self.__nickIndex = -1 |
85 self.__nickName = "" |
84 self.__nickName = "" |
86 self.__server = None |
85 self.__server = None |
87 self.__registering = False |
86 self.__registering = False |
88 |
87 |
89 self.__connectionState = IrcWidget.ServerDisconnected |
88 self.__connectionState = IrcWidget.ServerDisconnected |
90 self.__sslErrorLock = False |
89 self.__sslErrorLock = False |
91 |
90 |
92 self.__buffer = "" |
91 self.__buffer = "" |
93 self.__userPrefix = {} |
92 self.__userPrefix = {} |
94 |
93 |
95 self.__socket = None |
94 self.__socket = None |
96 if SSL_AVAILABLE: |
95 if SSL_AVAILABLE: |
97 self.__sslErrorHandler = EricSslErrorHandler(self) |
96 self.__sslErrorHandler = EricSslErrorHandler(self) |
98 else: |
97 else: |
99 self.__sslErrorHandler = None |
98 self.__sslErrorHandler = None |
100 |
99 |
101 self.__patterns = [ |
100 self.__patterns = [ |
102 # :foo_!n=foo@foohost.bar.net PRIVMSG bar_ :some long message |
101 # :foo_!n=foo@foohost.bar.net PRIVMSG bar_ :some long message |
103 (re.compile(r":([^!]+)!([^ ]+)\sPRIVMSG\s([^ ]+)\s:(.*)"), |
102 (re.compile(r":([^!]+)!([^ ]+)\sPRIVMSG\s([^ ]+)\s:(.*)"), self.__query), |
104 self.__query), |
|
105 # :foo.bar.net COMMAND some message |
103 # :foo.bar.net COMMAND some message |
106 (re.compile(r""":([^ ]+)\s+([A-Z]+)\s+(.+)"""), |
104 (re.compile(r""":([^ ]+)\s+([A-Z]+)\s+(.+)"""), self.__handleNamedMessage), |
107 self.__handleNamedMessage), |
|
108 # :foo.bar.net 123 * :info |
105 # :foo.bar.net 123 * :info |
109 (re.compile(r""":([^ ]+)\s+(\d{3})\s+(.+)"""), |
106 (re.compile(r""":([^ ]+)\s+(\d{3})\s+(.+)"""), self.__handleNumericMessage), |
110 self.__handleNumericMessage), |
|
111 # PING :ping message |
107 # PING :ping message |
112 (re.compile(r"""PING\s+:(.*)"""), self.__ping), |
108 (re.compile(r"""PING\s+:(.*)"""), self.__ping), |
113 ] |
109 ] |
114 self.__prefixRe = re.compile(r""".*\sPREFIX=\((.*)\)([^ ]+).*""") |
110 self.__prefixRe = re.compile(r""".*\sPREFIX=\((.*)\)([^ ]+).*""") |
115 self.__chanTypesRe = re.compile(r""".*\sCHANTYPES=([^ ]+).*""") |
111 self.__chanTypesRe = re.compile(r""".*\sCHANTYPES=([^ ]+).*""") |
116 |
112 |
117 ircPic = UI.PixmapCache.getPixmap("irc128") |
113 ircPic = UI.PixmapCache.getPixmap("irc128") |
118 self.__emptyLabel = QLabel() |
114 self.__emptyLabel = QLabel() |
119 self.__emptyLabel.setPixmap(ircPic) |
115 self.__emptyLabel.setPixmap(ircPic) |
120 self.__emptyLabel.setAlignment( |
116 self.__emptyLabel.setAlignment( |
121 Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignHCenter) |
117 Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignHCenter |
|
118 ) |
122 self.channelsWidget.addTab(self.__emptyLabel, "") |
119 self.channelsWidget.addTab(self.__emptyLabel, "") |
123 |
120 |
124 # all initialized, do connections now |
121 # all initialized, do connections now |
125 self.__ircNetworkManager.dataChanged.connect(self.__networkDataChanged) |
122 self.__ircNetworkManager.dataChanged.connect(self.__networkDataChanged) |
126 self.networkWidget.initialize(self.__ircNetworkManager) |
123 self.networkWidget.initialize(self.__ircNetworkManager) |
127 self.networkWidget.connectNetwork.connect(self.__connectNetwork) |
124 self.networkWidget.connectNetwork.connect(self.__connectNetwork) |
128 self.networkWidget.editNetwork.connect(self.__editNetwork) |
125 self.networkWidget.editNetwork.connect(self.__editNetwork) |
129 self.networkWidget.joinChannel.connect(self.joinChannel) |
126 self.networkWidget.joinChannel.connect(self.joinChannel) |
130 self.networkWidget.nickChanged.connect(self.__changeNick) |
127 self.networkWidget.nickChanged.connect(self.__changeNick) |
131 self.networkWidget.sendData.connect(self.__send) |
128 self.networkWidget.sendData.connect(self.__send) |
132 self.networkWidget.away.connect(self.__away) |
129 self.networkWidget.away.connect(self.__away) |
133 self.networkWidget.autoConnected.connect(self.autoConnected) |
130 self.networkWidget.autoConnected.connect(self.autoConnected) |
134 |
131 |
135 def shutdown(self): |
132 def shutdown(self): |
136 """ |
133 """ |
137 Public method to shut down the widget. |
134 Public method to shut down the widget. |
138 |
135 |
139 @return flag indicating successful shutdown (boolean) |
136 @return flag indicating successful shutdown (boolean) |
140 """ |
137 """ |
141 if self.__server: |
138 if self.__server: |
142 if Preferences.getIrc("AskOnShutdown"): |
139 if Preferences.getIrc("AskOnShutdown"): |
143 ok = EricMessageBox.yesNo( |
140 ok = EricMessageBox.yesNo( |
144 self, |
141 self, |
145 self.tr("Disconnect from Server"), |
142 self.tr("Disconnect from Server"), |
146 self.tr( |
143 self.tr( |
147 """<p>Do you really want to disconnect from""" |
144 """<p>Do you really want to disconnect from""" |
148 """ <b>{0}</b>?</p><p>All channels will be closed.""" |
145 """ <b>{0}</b>?</p><p>All channels will be closed.""" |
149 """</p>""").format(self.__server.getName())) |
146 """</p>""" |
|
147 ).format(self.__server.getName()), |
|
148 ) |
150 else: |
149 else: |
151 ok = True |
150 ok = True |
152 if ok: |
151 if ok: |
153 self.__connectNetwork("", False, True) |
152 self.__connectNetwork("", False, True) |
154 else: |
153 else: |
155 ok = True |
154 ok = True |
156 |
155 |
157 if ok: |
156 if ok: |
158 self.__ircNetworkManager.close() |
157 self.__ircNetworkManager.close() |
159 |
158 |
160 return ok |
159 return ok |
161 |
160 |
162 def autoConnect(self): |
161 def autoConnect(self): |
163 """ |
162 """ |
164 Public method to initiate the IRC auto connection. |
163 Public method to initiate the IRC auto connection. |
165 """ |
164 """ |
166 self.networkWidget.autoConnect() |
165 self.networkWidget.autoConnect() |
167 |
166 |
168 def __connectNetwork(self, name, connect, silent): |
167 def __connectNetwork(self, name, connect, silent): |
169 """ |
168 """ |
170 Private slot to connect to or disconnect from the given network. |
169 Private slot to connect to or disconnect from the given network. |
171 |
170 |
172 @param name name of the network to connect to (string) |
171 @param name name of the network to connect to (string) |
173 @param connect flag indicating to connect (boolean) |
172 @param connect flag indicating to connect (boolean) |
174 @param silent flag indicating a silent connect/disconnect (boolean) |
173 @param silent flag indicating a silent connect/disconnect (boolean) |
175 """ |
174 """ |
176 if connect: |
175 if connect: |
177 network = self.__ircNetworkManager.getNetwork(name) |
176 network = self.__ircNetworkManager.getNetwork(name) |
178 if network: |
177 if network: |
179 self.__server = network.getServer() |
178 self.__server = network.getServer() |
180 self.__identityName = network.getIdentityName() |
179 self.__identityName = network.getIdentityName() |
181 identity = self.__ircNetworkManager.getIdentity( |
180 identity = self.__ircNetworkManager.getIdentity(self.__identityName) |
182 self.__identityName) |
|
183 if identity: |
181 if identity: |
184 self.__userName = identity.getIdent() |
182 self.__userName = identity.getIdent() |
185 self.__quitMessage = identity.getQuitMessage() |
183 self.__quitMessage = identity.getQuitMessage() |
186 if self.__server: |
184 if self.__server: |
187 useSSL = self.__server.useSSL() |
185 useSSL = self.__server.useSSL() |
191 self.tr("SSL Connection"), |
189 self.tr("SSL Connection"), |
192 self.tr( |
190 self.tr( |
193 """An encrypted connection to the IRC""" |
191 """An encrypted connection to the IRC""" |
194 """ network was requested but SSL is not""" |
192 """ network was requested but SSL is not""" |
195 """ available. Please change the server""" |
193 """ available. Please change the server""" |
196 """ configuration.""")) |
194 """ configuration.""" |
|
195 ), |
|
196 ) |
197 return |
197 return |
198 |
198 |
199 if useSSL: |
199 if useSSL: |
200 # create SSL socket |
200 # create SSL socket |
201 self.__socket = QSslSocket(self) |
201 self.__socket = QSslSocket(self) |
202 self.__socket.encrypted.connect( |
202 self.__socket.encrypted.connect(self.__hostConnected) |
203 self.__hostConnected) |
203 self.__socket.sslErrors.connect(self.__sslErrors) |
204 self.__socket.sslErrors.connect( |
|
205 self.__sslErrors) |
|
206 else: |
204 else: |
207 # create TCP socket |
205 # create TCP socket |
208 self.__socket = QTcpSocket(self) |
206 self.__socket = QTcpSocket(self) |
209 self.__socket.connected.connect( |
207 self.__socket.connected.connect(self.__hostConnected) |
210 self.__hostConnected) |
208 self.__socket.hostFound.connect(self.__hostFound) |
211 self.__socket.hostFound.connect( |
209 self.__socket.disconnected.connect(self.__hostDisconnected) |
212 self.__hostFound) |
210 self.__socket.readyRead.connect(self.__readyRead) |
213 self.__socket.disconnected.connect( |
211 self.__socket.errorOccurred.connect(self.__tcpError) |
214 self.__hostDisconnected) |
212 |
215 self.__socket.readyRead.connect( |
|
216 self.__readyRead) |
|
217 self.__socket.errorOccurred.connect( |
|
218 self.__tcpError) |
|
219 |
|
220 self.__connectionState = IrcWidget.ServerConnecting |
213 self.__connectionState = IrcWidget.ServerConnecting |
221 if useSSL: |
214 if useSSL: |
222 self.networkWidget.addServerMessage( |
215 self.networkWidget.addServerMessage( |
223 self.tr("Info"), |
216 self.tr("Info"), |
224 self.tr("Looking for server {0} (port {1})" |
217 self.tr( |
225 " using an SSL encrypted connection" |
218 "Looking for server {0} (port {1})" |
226 "...").format(self.__server.getName(), |
219 " using an SSL encrypted connection" |
227 self.__server.getPort())) |
220 "..." |
|
221 ).format( |
|
222 self.__server.getName(), self.__server.getPort() |
|
223 ), |
|
224 ) |
228 self.__socket.connectToHostEncrypted( |
225 self.__socket.connectToHostEncrypted( |
229 self.__server.getName(), |
226 self.__server.getName(), self.__server.getPort() |
230 self.__server.getPort() |
|
231 ) |
227 ) |
232 else: |
228 else: |
233 self.networkWidget.addServerMessage( |
229 self.networkWidget.addServerMessage( |
234 self.tr("Info"), |
230 self.tr("Info"), |
235 self.tr( |
231 self.tr("Looking for server {0} (port {1})...").format( |
236 "Looking for server {0} (port {1})...") |
232 self.__server.getName(), self.__server.getPort() |
237 .format( |
233 ), |
238 self.__server.getName(), |
234 ) |
239 self.__server.getPort())) |
|
240 self.__socket.connectToHost( |
235 self.__socket.connectToHost( |
241 self.__server.getName(), |
236 self.__server.getName(), self.__server.getPort() |
242 self.__server.getPort()) |
237 ) |
243 else: |
238 else: |
244 if silent: |
239 if silent: |
245 ok = True |
240 ok = True |
246 else: |
241 else: |
247 ok = EricMessageBox.yesNo( |
242 ok = EricMessageBox.yesNo( |
248 self, |
243 self, |
249 self.tr("Disconnect from Server"), |
244 self.tr("Disconnect from Server"), |
250 self.tr("""<p>Do you really want to disconnect from""" |
245 self.tr( |
251 """ <b>{0}</b>?</p><p>All channels will be""" |
246 """<p>Do you really want to disconnect from""" |
252 """ closed.</p>""") |
247 """ <b>{0}</b>?</p><p>All channels will be""" |
253 .format(self.__server.getName())) |
248 """ closed.</p>""" |
|
249 ).format(self.__server.getName()), |
|
250 ) |
254 if ok: |
251 if ok: |
255 if self.__server is not None: |
252 if self.__server is not None: |
256 self.networkWidget.addServerMessage( |
253 self.networkWidget.addServerMessage( |
257 self.tr("Info"), |
254 self.tr("Info"), |
258 self.tr("Disconnecting from server {0}...").format( |
255 self.tr("Disconnecting from server {0}...").format( |
259 self.__server.getName())) |
256 self.__server.getName() |
|
257 ), |
|
258 ) |
260 elif name: |
259 elif name: |
261 self.networkWidget.addServerMessage( |
260 self.networkWidget.addServerMessage( |
262 self.tr("Info"), |
261 self.tr("Info"), |
263 self.tr("Disconnecting from network {0}...").format( |
262 self.tr("Disconnecting from network {0}...").format(name), |
264 name)) |
263 ) |
265 else: |
264 else: |
266 self.networkWidget.addServerMessage( |
265 self.networkWidget.addServerMessage( |
267 self.tr("Info"), |
266 self.tr("Info"), self.tr("Disconnecting from server.") |
268 self.tr("Disconnecting from server.")) |
267 ) |
269 self.__closeAllChannels() |
268 self.__closeAllChannels() |
270 self.__send("QUIT :" + self.__quitMessage) |
269 self.__send("QUIT :" + self.__quitMessage) |
271 if self.__socket: |
270 if self.__socket: |
272 self.__socket.flush() |
271 self.__socket.flush() |
273 self.__socket.close() |
272 self.__socket.close() |
276 self.__socket.deleteLater() |
275 self.__socket.deleteLater() |
277 self.__socket = None |
276 self.__socket = None |
278 self.__userName = "" |
277 self.__userName = "" |
279 self.__identityName = "" |
278 self.__identityName = "" |
280 self.__quitMessage = "" |
279 self.__quitMessage = "" |
281 |
280 |
282 def __editNetwork(self, name): |
281 def __editNetwork(self, name): |
283 """ |
282 """ |
284 Private slot to edit the network configuration. |
283 Private slot to edit the network configuration. |
285 |
284 |
286 @param name name of the network to edit (string) |
285 @param name name of the network to edit (string) |
287 """ |
286 """ |
288 from .IrcNetworkListDialog import IrcNetworkListDialog |
287 from .IrcNetworkListDialog import IrcNetworkListDialog |
|
288 |
289 dlg = IrcNetworkListDialog(self.__ircNetworkManager, self) |
289 dlg = IrcNetworkListDialog(self.__ircNetworkManager, self) |
290 dlg.exec() |
290 dlg.exec() |
291 |
291 |
292 def __networkDataChanged(self): |
292 def __networkDataChanged(self): |
293 """ |
293 """ |
294 Private slot handling changes of the network and identity definitions. |
294 Private slot handling changes of the network and identity definitions. |
295 """ |
295 """ |
296 identity = self.__ircNetworkManager.getIdentity(self.__identityName) |
296 identity = self.__ircNetworkManager.getIdentity(self.__identityName) |
297 if identity: |
297 if identity: |
298 partMsg = identity.getPartMessage() |
298 partMsg = identity.getPartMessage() |
299 for channel in self.__channelList: |
299 for channel in self.__channelList: |
300 channel.setPartMessage(partMsg) |
300 channel.setPartMessage(partMsg) |
301 |
301 |
302 def joinChannel(self, name, key=""): |
302 def joinChannel(self, name, key=""): |
303 """ |
303 """ |
304 Public slot to join a channel. |
304 Public slot to join a channel. |
305 |
305 |
306 @param name name of the channel (string) |
306 @param name name of the channel (string) |
307 @param key key of the channel (string) |
307 @param key key of the channel (string) |
308 """ |
308 """ |
309 # step 1: check, if this channel is already joined |
309 # step 1: check, if this channel is already joined |
310 for channel in self.__channelList: |
310 for channel in self.__channelList: |
311 if channel.name() == name: |
311 if channel.name() == name: |
312 return |
312 return |
313 |
313 |
314 from .IrcChannelWidget import IrcChannelWidget |
314 from .IrcChannelWidget import IrcChannelWidget |
|
315 |
315 channel = IrcChannelWidget(self) |
316 channel = IrcChannelWidget(self) |
316 channel.setName(name) |
317 channel.setName(name) |
317 channel.setUserName(self.__nickName) |
318 channel.setUserName(self.__nickName) |
318 identity = self.__ircNetworkManager.getIdentity(self.__identityName) |
319 identity = self.__ircNetworkManager.getIdentity(self.__identityName) |
319 if identity: |
320 if identity: |
320 channel.setPartMessage(identity.getPartMessage()) |
321 channel.setPartMessage(identity.getPartMessage()) |
321 channel.setUserPrivilegePrefix(self.__userPrefix) |
322 channel.setUserPrivilegePrefix(self.__userPrefix) |
322 channel.initAutoWho() |
323 channel.initAutoWho() |
323 |
324 |
324 channel.sendData.connect(self.__send) |
325 channel.sendData.connect(self.__send) |
325 channel.sendCtcpRequest.connect(self.__sendCtcpRequest) |
326 channel.sendCtcpRequest.connect(self.__sendCtcpRequest) |
326 channel.sendCtcpReply.connect(self.__sendCtcpReply) |
327 channel.sendCtcpReply.connect(self.__sendCtcpReply) |
327 channel.channelClosed.connect(self.__closeChannel) |
328 channel.channelClosed.connect(self.__closeChannel) |
328 channel.openPrivateChat.connect(self.__openPrivate) |
329 channel.openPrivateChat.connect(self.__openPrivate) |
329 channel.awayCommand.connect(self.networkWidget.handleAwayCommand) |
330 channel.awayCommand.connect(self.networkWidget.handleAwayCommand) |
330 channel.leaveChannels.connect(self.__leaveChannels) |
331 channel.leaveChannels.connect(self.__leaveChannels) |
331 channel.leaveAllChannels.connect(self.__leaveAllChannels) |
332 channel.leaveAllChannels.connect(self.__leaveAllChannels) |
332 |
333 |
333 self.channelsWidget.addTab(channel, name) |
334 self.channelsWidget.addTab(channel, name) |
334 self.__channelList.append(channel) |
335 self.__channelList.append(channel) |
335 self.channelsWidget.setCurrentWidget(channel) |
336 self.channelsWidget.setCurrentWidget(channel) |
336 |
337 |
337 joinCommand = ["JOIN", name] |
338 joinCommand = ["JOIN", name] |
338 if key: |
339 if key: |
339 joinCommand.append(key) |
340 joinCommand.append(key) |
340 self.__send(" ".join(joinCommand)) |
341 self.__send(" ".join(joinCommand)) |
341 self.__send("MODE " + name) |
342 self.__send("MODE " + name) |
342 |
343 |
343 emptyIndex = self.channelsWidget.indexOf(self.__emptyLabel) |
344 emptyIndex = self.channelsWidget.indexOf(self.__emptyLabel) |
344 if emptyIndex > -1: |
345 if emptyIndex > -1: |
345 self.channelsWidget.removeTab(emptyIndex) |
346 self.channelsWidget.removeTab(emptyIndex) |
346 self.__leaveButton.setEnabled(True) |
347 self.__leaveButton.setEnabled(True) |
347 self.channelsWidget.setTabsClosable(True) |
348 self.channelsWidget.setTabsClosable(True) |
348 |
349 |
349 def __query(self, match): |
350 def __query(self, match): |
350 """ |
351 """ |
351 Private method to handle a new private connection. |
352 Private method to handle a new private connection. |
352 |
353 |
353 @param match reference to the match object |
354 @param match reference to the match object |
354 @return flag indicating, if the message was handled (boolean) |
355 @return flag indicating, if the message was handled (boolean) |
355 """ |
356 """ |
356 # group(1) sender user name |
357 # group(1) sender user name |
357 # group(2) sender user@host |
358 # group(2) sender user@host |
358 # group(3) target nick |
359 # group(3) target nick |
359 # group(4) message |
360 # group(4) message |
360 if match.group(4).startswith("\x01"): |
361 if match.group(4).startswith("\x01"): |
361 return self.__handleCtcp(match) |
362 return self.__handleCtcp(match) |
362 |
363 |
363 self.__openPrivate(match.group(1)) |
364 self.__openPrivate(match.group(1)) |
364 # the above call sets the new channel as the current widget |
365 # the above call sets the new channel as the current widget |
365 channel = self.channelsWidget.currentWidget() |
366 channel = self.channelsWidget.currentWidget() |
366 channel.addMessage(match.group(1), match.group(4)) |
367 channel.addMessage(match.group(1), match.group(4)) |
367 channel.setPrivateInfo( |
368 channel.setPrivateInfo("{0} - {1}".format(match.group(1), match.group(2))) |
368 "{0} - {1}".format(match.group(1), match.group(2))) |
369 |
369 |
|
370 return True |
370 return True |
371 |
371 |
372 @pyqtSlot(str) |
372 @pyqtSlot(str) |
373 def __openPrivate(self, name): |
373 def __openPrivate(self, name): |
374 """ |
374 """ |
375 Private slot to open a private chat with the given user. |
375 Private slot to open a private chat with the given user. |
376 |
376 |
377 @param name name of the user (string) |
377 @param name name of the user (string) |
378 """ |
378 """ |
379 from .IrcChannelWidget import IrcChannelWidget |
379 from .IrcChannelWidget import IrcChannelWidget |
|
380 |
380 channel = IrcChannelWidget(self) |
381 channel = IrcChannelWidget(self) |
381 channel.setName(self.__nickName) |
382 channel.setName(self.__nickName) |
382 channel.setUserName(self.__nickName) |
383 channel.setUserName(self.__nickName) |
383 identity = self.__ircNetworkManager.getIdentity(self.__identityName) |
384 identity = self.__ircNetworkManager.getIdentity(self.__identityName) |
384 if identity: |
385 if identity: |
385 channel.setPartMessage(identity.getPartMessage()) |
386 channel.setPartMessage(identity.getPartMessage()) |
386 channel.setUserPrivilegePrefix(self.__userPrefix) |
387 channel.setUserPrivilegePrefix(self.__userPrefix) |
387 channel.setPrivate(True, name) |
388 channel.setPrivate(True, name) |
388 channel.addUsers([name, self.__nickName]) |
389 channel.addUsers([name, self.__nickName]) |
389 |
390 |
390 channel.sendData.connect(self.__send) |
391 channel.sendData.connect(self.__send) |
391 channel.sendCtcpRequest.connect(self.__sendCtcpRequest) |
392 channel.sendCtcpRequest.connect(self.__sendCtcpRequest) |
392 channel.sendCtcpReply.connect(self.__sendCtcpReply) |
393 channel.sendCtcpReply.connect(self.__sendCtcpReply) |
393 channel.channelClosed.connect(self.__closeChannel) |
394 channel.channelClosed.connect(self.__closeChannel) |
394 channel.awayCommand.connect(self.networkWidget.handleAwayCommand) |
395 channel.awayCommand.connect(self.networkWidget.handleAwayCommand) |
395 channel.leaveChannels.connect(self.__leaveChannels) |
396 channel.leaveChannels.connect(self.__leaveChannels) |
396 channel.leaveAllChannels.connect(self.__leaveAllChannels) |
397 channel.leaveAllChannels.connect(self.__leaveAllChannels) |
397 |
398 |
398 self.channelsWidget.addTab(channel, name) |
399 self.channelsWidget.addTab(channel, name) |
399 self.__channelList.append(channel) |
400 self.__channelList.append(channel) |
400 self.channelsWidget.setCurrentWidget(channel) |
401 self.channelsWidget.setCurrentWidget(channel) |
401 |
402 |
402 @pyqtSlot() |
403 @pyqtSlot() |
403 def __leaveChannel(self): |
404 def __leaveChannel(self): |
404 """ |
405 """ |
405 Private slot to leave a channel and close the associated tab. |
406 Private slot to leave a channel and close the associated tab. |
406 """ |
407 """ |
407 channel = self.channelsWidget.currentWidget() |
408 channel = self.channelsWidget.currentWidget() |
408 channel.requestLeave() |
409 channel.requestLeave() |
409 |
410 |
410 @pyqtSlot(list) |
411 @pyqtSlot(list) |
411 def __leaveChannels(self, channelNames): |
412 def __leaveChannels(self, channelNames): |
412 """ |
413 """ |
413 Private slot to leave a list of channels and close their associated |
414 Private slot to leave a list of channels and close their associated |
414 tabs. |
415 tabs. |
415 |
416 |
416 @param channelNames list of channels to leave |
417 @param channelNames list of channels to leave |
417 @type list of str |
418 @type list of str |
418 """ |
419 """ |
419 for channelName in channelNames: |
420 for channelName in channelNames: |
420 for channel in self.__channelList: |
421 for channel in self.__channelList: |
421 if channel.name() == channelName: |
422 if channel.name() == channelName: |
422 channel.leaveChannel() |
423 channel.leaveChannel() |
423 |
424 |
424 @pyqtSlot() |
425 @pyqtSlot() |
425 def __leaveAllChannels(self): |
426 def __leaveAllChannels(self): |
426 """ |
427 """ |
427 Private slot to leave all channels and close their tabs. |
428 Private slot to leave all channels and close their tabs. |
428 """ |
429 """ |
429 while self.__channelList: |
430 while self.__channelList: |
430 channel = self.__channelList[0] |
431 channel = self.__channelList[0] |
431 channel.leaveChannel() |
432 channel.leaveChannel() |
432 |
433 |
433 def __closeAllChannels(self): |
434 def __closeAllChannels(self): |
434 """ |
435 """ |
435 Private method to close all channels. |
436 Private method to close all channels. |
436 """ |
437 """ |
437 while self.__channelList: |
438 while self.__channelList: |
438 channel = self.__channelList.pop() |
439 channel = self.__channelList.pop() |
439 self.channelsWidget.removeTab(self.channelsWidget.indexOf(channel)) |
440 self.channelsWidget.removeTab(self.channelsWidget.indexOf(channel)) |
440 channel.deleteLater() |
441 channel.deleteLater() |
441 channel = None |
442 channel = None |
442 |
443 |
443 self.channelsWidget.addTab(self.__emptyLabel, "") |
444 self.channelsWidget.addTab(self.__emptyLabel, "") |
444 self.__emptyLabel.show() |
445 self.__emptyLabel.show() |
445 self.__leaveButton.setEnabled(False) |
446 self.__leaveButton.setEnabled(False) |
446 self.channelsWidget.setTabsClosable(False) |
447 self.channelsWidget.setTabsClosable(False) |
447 |
448 |
448 def __closeChannel(self, name): |
449 def __closeChannel(self, name): |
449 """ |
450 """ |
450 Private slot handling the closing of a channel. |
451 Private slot handling the closing of a channel. |
451 |
452 |
452 @param name name of the closed channel (string) |
453 @param name name of the closed channel (string) |
453 """ |
454 """ |
454 for channel in self.__channelList: |
455 for channel in self.__channelList: |
455 if channel.name() == name: |
456 if channel.name() == name: |
456 self.channelsWidget.removeTab( |
457 self.channelsWidget.removeTab(self.channelsWidget.indexOf(channel)) |
457 self.channelsWidget.indexOf(channel)) |
|
458 self.__channelList.remove(channel) |
458 self.__channelList.remove(channel) |
459 channel.deleteLater() |
459 channel.deleteLater() |
460 |
460 |
461 if self.channelsWidget.count() == 0: |
461 if self.channelsWidget.count() == 0: |
462 self.channelsWidget.addTab(self.__emptyLabel, "") |
462 self.channelsWidget.addTab(self.__emptyLabel, "") |
463 self.__emptyLabel.show() |
463 self.__emptyLabel.show() |
464 self.__leaveButton.setEnabled(False) |
464 self.__leaveButton.setEnabled(False) |
465 self.channelsWidget.setTabsClosable(False) |
465 self.channelsWidget.setTabsClosable(False) |
466 |
466 |
467 @pyqtSlot(int) |
467 @pyqtSlot(int) |
468 def on_channelsWidget_tabCloseRequested(self, index): |
468 def on_channelsWidget_tabCloseRequested(self, index): |
469 """ |
469 """ |
470 Private slot to close a channel by pressing the close button of |
470 Private slot to close a channel by pressing the close button of |
471 the channels widget. |
471 the channels widget. |
472 |
472 |
473 @param index index of the tab to be closed (integer) |
473 @param index index of the tab to be closed (integer) |
474 """ |
474 """ |
475 channel = self.channelsWidget.widget(index) |
475 channel = self.channelsWidget.widget(index) |
476 channel.requestLeave() |
476 channel.requestLeave() |
477 |
477 |
478 def __send(self, data): |
478 def __send(self, data): |
479 """ |
479 """ |
480 Private slot to send data to the IRC server. |
480 Private slot to send data to the IRC server. |
481 |
481 |
482 @param data data to be sent (string) |
482 @param data data to be sent (string) |
483 """ |
483 """ |
484 if self.__socket: |
484 if self.__socket: |
485 self.__socket.write( |
485 self.__socket.write(QByteArray("{0}\r\n".format(data).encode("utf-8"))) |
486 QByteArray("{0}\r\n".format(data).encode("utf-8"))) |
486 |
487 |
|
488 def __sendCtcpRequest(self, receiver, request, arguments): |
487 def __sendCtcpRequest(self, receiver, request, arguments): |
489 """ |
488 """ |
490 Private slot to send a CTCP request. |
489 Private slot to send a CTCP request. |
491 |
490 |
492 @param receiver nick name of the receiver |
491 @param receiver nick name of the receiver |
493 @type str |
492 @type str |
494 @param request CTCP request to be sent |
493 @param request CTCP request to be sent |
495 @type str |
494 @type str |
496 @param arguments arguments to be sent |
495 @param arguments arguments to be sent |
497 @type str |
496 @type str |
498 """ |
497 """ |
499 request = request.upper() |
498 request = request.upper() |
500 if request == "PING": |
499 if request == "PING": |
501 arguments = "Eric IRC {0}".format( |
500 arguments = "Eric IRC {0}".format(QDateTime.currentMSecsSinceEpoch()) |
502 QDateTime.currentMSecsSinceEpoch()) |
501 |
503 |
502 self.__send("PRIVMSG {0} :\x01{1} {2}\x01".format(receiver, request, arguments)) |
504 self.__send("PRIVMSG {0} :\x01{1} {2}\x01".format( |
503 |
505 receiver, request, arguments)) |
|
506 |
|
507 def __sendCtcpReply(self, receiver, text): |
504 def __sendCtcpReply(self, receiver, text): |
508 """ |
505 """ |
509 Private slot to send a CTCP reply. |
506 Private slot to send a CTCP reply. |
510 |
507 |
511 @param receiver nick name of the receiver |
508 @param receiver nick name of the receiver |
512 @type str |
509 @type str |
513 @param text text to be sent |
510 @param text text to be sent |
514 @type str |
511 @type str |
515 """ |
512 """ |
516 self.__send("NOTICE {0} :\x01{1}\x01".format(receiver, text)) |
513 self.__send("NOTICE {0} :\x01{1}\x01".format(receiver, text)) |
517 |
514 |
518 def __hostFound(self): |
515 def __hostFound(self): |
519 """ |
516 """ |
520 Private slot to indicate the host was found. |
517 Private slot to indicate the host was found. |
521 """ |
518 """ |
522 self.networkWidget.addServerMessage( |
519 self.networkWidget.addServerMessage( |
523 self.tr("Info"), |
520 self.tr("Info"), self.tr("Server found,connecting...") |
524 self.tr("Server found,connecting...")) |
521 ) |
525 |
522 |
526 def __hostConnected(self): |
523 def __hostConnected(self): |
527 """ |
524 """ |
528 Private slot to log in to the server after the connection was |
525 Private slot to log in to the server after the connection was |
529 established. |
526 established. |
530 """ |
527 """ |
531 self.networkWidget.addServerMessage( |
528 self.networkWidget.addServerMessage( |
532 self.tr("Info"), |
529 self.tr("Info"), self.tr("Connected,logging in...") |
533 self.tr("Connected,logging in...")) |
530 ) |
534 self.networkWidget.setConnected(True) |
531 self.networkWidget.setConnected(True) |
535 |
532 |
536 self.__registering = True |
533 self.__registering = True |
537 serverPassword = self.__server.getPassword() |
534 serverPassword = self.__server.getPassword() |
538 if serverPassword: |
535 if serverPassword: |
539 self.__send("PASS " + serverPassword) |
536 self.__send("PASS " + serverPassword) |
540 |
537 |
541 identity = self.__ircNetworkManager.getIdentity( |
538 identity = self.__ircNetworkManager.getIdentity(self.__identityName) |
542 self.__identityName) |
|
543 nick = self.networkWidget.getNickname() |
539 nick = self.networkWidget.getNickname() |
544 if not nick and identity: |
540 if not nick and identity: |
545 self.__nickIndex = 0 |
541 self.__nickIndex = 0 |
546 try: |
542 try: |
547 nick = identity.getNickNames()[self.__nickIndex] |
543 nick = identity.getNickNames()[self.__nickIndex] |
611 # Oops, the message wasn't handled |
606 # Oops, the message wasn't handled |
612 self.networkWidget.addErrorMessage( |
607 self.networkWidget.addErrorMessage( |
613 self.tr("Message Error"), |
608 self.tr("Message Error"), |
614 self.tr( |
609 self.tr( |
615 "Unknown message received from server:" |
610 "Unknown message received from server:" |
616 "<br/>{0}").format(line)) |
611 "<br/>{0}" |
617 |
612 ).format(line), |
|
613 ) |
|
614 |
618 self.__updateUsersCount() |
615 self.__updateUsersCount() |
619 self.__buffer = "" |
616 self.__buffer = "" |
620 |
617 |
621 def __handleCtcpReply(self, match): |
618 def __handleCtcpReply(self, match): |
622 """ |
619 """ |
623 Private method to handle a server message containing a CTCP reply. |
620 Private method to handle a server message containing a CTCP reply. |
624 |
621 |
625 @param match reference to the match object |
622 @param match reference to the match object |
626 """ |
623 """ |
627 if "!" in match.group(1): |
624 if "!" in match.group(1): |
628 sender = match.group(1).split("!", 1)[0] |
625 sender = match.group(1).split("!", 1)[0] |
629 |
626 |
630 try: |
627 try: |
631 ctcpCommand = match.group(3).split(":", 1)[1] |
628 ctcpCommand = match.group(3).split(":", 1)[1] |
632 except IndexError: |
629 except IndexError: |
633 ctcpCommand = match.group(3) |
630 ctcpCommand = match.group(3) |
634 ctcpCommand = ctcpCommand[1:].split("\x01", 1)[0] |
631 ctcpCommand = ctcpCommand[1:].split("\x01", 1)[0] |
635 if " " in ctcpCommand: |
632 if " " in ctcpCommand: |
636 ctcpReply, ctcpArg = ctcpCommand.split(" ", 1) |
633 ctcpReply, ctcpArg = ctcpCommand.split(" ", 1) |
637 else: |
634 else: |
638 ctcpReply, ctcpArg = ctcpCommand, "" |
635 ctcpReply, ctcpArg = ctcpCommand, "" |
639 ctcpReply = ctcpReply.upper() |
636 ctcpReply = ctcpReply.upper() |
640 |
637 |
641 if ctcpReply == "PING" and ctcpArg.startswith("Eric IRC "): |
638 if ctcpReply == "PING" and ctcpArg.startswith("Eric IRC "): |
642 # it is a response to a ping request |
639 # it is a response to a ping request |
643 pingDateTime = int(ctcpArg.split()[-1]) |
640 pingDateTime = int(ctcpArg.split()[-1]) |
644 latency = QDateTime.currentMSecsSinceEpoch() - pingDateTime |
641 latency = QDateTime.currentMSecsSinceEpoch() - pingDateTime |
645 self.networkWidget.addServerMessage( |
642 self.networkWidget.addServerMessage( |
646 self.tr("CTCP"), |
643 self.tr("CTCP"), |
647 self.tr( |
644 self.tr( |
648 "Received CTCP-PING response from {0} with latency" |
645 "Received CTCP-PING response from {0} with latency" |
649 " of {1} ms.").format(sender, latency)) |
646 " of {1} ms." |
|
647 ).format(sender, latency), |
|
648 ) |
650 else: |
649 else: |
651 self.networkWidget.addServerMessage( |
650 self.networkWidget.addServerMessage( |
652 self.tr("CTCP"), |
651 self.tr("CTCP"), |
653 self.tr( |
652 self.tr("Received unknown CTCP-{0} response from {1}.").format( |
654 "Received unknown CTCP-{0} response from {1}.") |
653 ctcpReply, sender |
655 .format(ctcpReply, sender)) |
654 ), |
656 |
655 ) |
|
656 |
657 def __handleNamedMessage(self, match): |
657 def __handleNamedMessage(self, match): |
658 """ |
658 """ |
659 Private method to handle a server message containing a message name. |
659 Private method to handle a server message containing a message name. |
660 |
660 |
661 @param match reference to the match object |
661 @param match reference to the match object |
662 @return flag indicating, if the message was handled (boolean) |
662 @return flag indicating, if the message was handled (boolean) |
663 """ |
663 """ |
664 name = match.group(2) |
664 name = match.group(2) |
665 if name == "NOTICE": |
665 if name == "NOTICE": |
666 try: |
666 try: |
667 msg = match.group(3).split(":", 1)[1] |
667 msg = match.group(3).split(":", 1)[1] |
668 except IndexError: |
668 except IndexError: |
669 msg = match.group(3) |
669 msg = match.group(3) |
670 |
670 |
671 if msg.startswith("\x01"): |
671 if msg.startswith("\x01"): |
672 self.__handleCtcpReply(match) |
672 self.__handleCtcpReply(match) |
673 return True |
673 return True |
674 |
674 |
675 if "!" in match.group(1): |
675 if "!" in match.group(1): |
676 name = match.group(1).split("!", 1)[0] |
676 name = match.group(1).split("!", 1)[0] |
677 msg = "-{0}- {1}".format(name, msg) |
677 msg = "-{0}- {1}".format(name, msg) |
678 self.networkWidget.addServerMessage(self.tr("Notice"), msg) |
678 self.networkWidget.addServerMessage(self.tr("Notice"), msg) |
679 return True |
679 return True |
681 self.__registering = False |
681 self.__registering = False |
682 if ":" in match.group(3): |
682 if ":" in match.group(3): |
683 # :foo MODE foo :+i |
683 # :foo MODE foo :+i |
684 name, modes = match.group(3).split(" :") |
684 name, modes = match.group(3).split(" :") |
685 sourceNick = match.group(1) |
685 sourceNick = match.group(1) |
686 if ( |
686 if not self.isChannelName(name) and name == self.__nickName: |
687 not self.isChannelName(name) and |
|
688 name == self.__nickName |
|
689 ): |
|
690 if sourceNick == self.__nickName: |
687 if sourceNick == self.__nickName: |
691 msg = self.tr( |
688 msg = self.tr( |
692 "You have set your personal modes to" |
689 "You have set your personal modes to" " <b>[{0}]</b>." |
693 " <b>[{0}]</b>.").format(modes) |
690 ).format(modes) |
694 else: |
691 else: |
695 msg = self.tr( |
692 msg = self.tr( |
696 "{0} has changed your personal modes to" |
693 "{0} has changed your personal modes to" " <b>[{1}]</b>." |
697 " <b>[{1}]</b>.").format(sourceNick, modes) |
694 ).format(sourceNick, modes) |
698 self.networkWidget.addServerMessage( |
695 self.networkWidget.addServerMessage( |
699 self.tr("Mode"), msg, filterMsg=False) |
696 self.tr("Mode"), msg, filterMsg=False |
|
697 ) |
700 return True |
698 return True |
701 elif name == "PART": |
699 elif name == "PART": |
702 nick = match.group(1).split("!", 1)[0] |
700 nick = match.group(1).split("!", 1)[0] |
703 if nick == self.__nickName: |
701 if nick == self.__nickName: |
704 channel = match.group(3).split(None, 1)[0] |
702 channel = match.group(3).split(None, 1)[0] |
705 self.networkWidget.addMessage( |
703 self.networkWidget.addMessage( |
706 self.tr("You have left channel {0}.").format(channel)) |
704 self.tr("You have left channel {0}.").format(channel) |
|
705 ) |
707 return True |
706 return True |
708 elif name == "QUIT": |
707 elif name == "QUIT": |
709 # don't do anything with it here |
708 # don't do anything with it here |
710 return True |
709 return True |
711 elif name == "NICK": |
710 elif name == "NICK": |
712 # :foo_!n=foo@foohost.bar.net NICK :newnick |
711 # :foo_!n=foo@foohost.bar.net NICK :newnick |
713 oldNick = match.group(1).split("!", 1)[0] |
712 oldNick = match.group(1).split("!", 1)[0] |
714 newNick = match.group(3).split(":", 1)[1] |
713 newNick = match.group(3).split(":", 1)[1] |
715 if oldNick == self.__nickName: |
714 if oldNick == self.__nickName: |
716 self.networkWidget.addMessage( |
715 self.networkWidget.addMessage( |
717 self.tr("You are now known as {0}.").format(newNick)) |
716 self.tr("You are now known as {0}.").format(newNick) |
|
717 ) |
718 self.__nickName = newNick |
718 self.__nickName = newNick |
719 self.networkWidget.setNickName(newNick) |
719 self.networkWidget.setNickName(newNick) |
720 else: |
720 else: |
721 self.networkWidget.addMessage( |
721 self.networkWidget.addMessage( |
722 self.tr("User {0} is now known as {1}.").format( |
722 self.tr("User {0} is now known as {1}.").format(oldNick, newNick) |
723 oldNick, newNick)) |
723 ) |
724 return True |
724 return True |
725 elif name == "PONG": |
725 elif name == "PONG": |
726 nick = match.group(3).split(":", 1)[1] |
726 nick = match.group(3).split(":", 1)[1] |
727 self.networkWidget.addMessage( |
727 self.networkWidget.addMessage( |
728 self.tr("Received PONG from {0}").format(nick)) |
728 self.tr("Received PONG from {0}").format(nick) |
|
729 ) |
729 return True |
730 return True |
730 elif name == "ERROR": |
731 elif name == "ERROR": |
731 self.networkWidget.addErrorMessage( |
732 self.networkWidget.addErrorMessage( |
732 self.tr("Server Error"), match.group(3).split(":", 1)[1]) |
733 self.tr("Server Error"), match.group(3).split(":", 1)[1] |
|
734 ) |
733 return True |
735 return True |
734 |
736 |
735 return False |
737 return False |
736 |
738 |
737 def __handleNumericMessage(self, match): |
739 def __handleNumericMessage(self, match): |
738 """ |
740 """ |
739 Private method to handle a server message containing a numeric code. |
741 Private method to handle a server message containing a numeric code. |
740 |
742 |
741 @param match reference to the match object |
743 @param match reference to the match object |
742 @return flag indicating, if the message was handled (boolean) |
744 @return flag indicating, if the message was handled (boolean) |
743 """ |
745 """ |
744 code = int(match.group(2)) |
746 code = int(match.group(2)) |
745 if code < 400: |
747 if code < 400: |
746 return self.__handleServerReply( |
748 return self.__handleServerReply(code, match.group(1), match.group(3)) |
747 code, match.group(1), match.group(3)) |
|
748 else: |
749 else: |
749 return self.__handleServerError( |
750 return self.__handleServerError(code, match.group(1), match.group(3)) |
750 code, match.group(1), match.group(3)) |
751 |
751 |
|
752 def __handleServerError(self, code, server, message): |
752 def __handleServerError(self, code, server, message): |
753 """ |
753 """ |
754 Private slot to handle a server error reply. |
754 Private slot to handle a server error reply. |
755 |
755 |
756 @param code numerical code sent by the server (integer) |
756 @param code numerical code sent by the server (integer) |
757 @param server name of the server (string) |
757 @param server name of the server (string) |
758 @param message message sent by the server (string) |
758 @param message message sent by the server (string) |
759 @return flag indicating, if the message was handled (boolean) |
759 @return flag indicating, if the message was handled (boolean) |
760 """ |
760 """ |
840 # extract the channel type prefixes |
839 # extract the channel type prefixes |
841 # ... CHANTYPES=# ... |
840 # ... CHANTYPES=# ... |
842 m = self.__chanTypesRe.match(message) |
841 m = self.__chanTypesRe.match(message) |
843 if m: |
842 if m: |
844 self.__setChannelTypePrefixes(m.group(1)) |
843 self.__setChannelTypePrefixes(m.group(1)) |
845 |
844 |
846 return True |
845 return True |
847 |
846 |
848 def __registerWithServices(self): |
847 def __registerWithServices(self): |
849 """ |
848 """ |
850 Private method to register to services. |
849 Private method to register to services. |
851 """ |
850 """ |
852 identity = self.__ircNetworkManager.getIdentity(self.__identityName) |
851 identity = self.__ircNetworkManager.getIdentity(self.__identityName) |
853 if identity: |
852 if identity: |
854 service = identity.getServiceName() |
853 service = identity.getServiceName() |
855 password = identity.getPassword() |
854 password = identity.getPassword() |
856 if service and password: |
855 if service and password: |
857 self.__send("PRIVMSG " + service + " :identify " + password) |
856 self.__send("PRIVMSG " + service + " :identify " + password) |
858 |
857 |
859 def __autoJoinChannels(self): |
858 def __autoJoinChannels(self): |
860 """ |
859 """ |
861 Private slot to join channels automatically once a server got |
860 Private slot to join channels automatically once a server got |
862 connected. |
861 connected. |
863 """ |
862 """ |
864 for channel in self.networkWidget.getNetworkChannels(): |
863 for channel in self.networkWidget.getNetworkChannels(): |
865 if channel.autoJoin(): |
864 if channel.autoJoin(): |
866 name = channel.getName() |
865 name = channel.getName() |
867 key = channel.getKey() |
866 key = channel.getKey() |
868 self.joinChannel(name, key) |
867 self.joinChannel(name, key) |
869 |
868 |
870 def __tcpError(self, error): |
869 def __tcpError(self, error): |
871 """ |
870 """ |
872 Private slot to handle errors reported by the TCP socket. |
871 Private slot to handle errors reported by the TCP socket. |
873 |
872 |
874 @param error error code reported by the socket |
873 @param error error code reported by the socket |
875 (QAbstractSocket.SocketError) |
874 (QAbstractSocket.SocketError) |
876 """ |
875 """ |
877 if error == QAbstractSocket.SocketError.RemoteHostClosedError: |
876 if error == QAbstractSocket.SocketError.RemoteHostClosedError: |
878 # ignore this one, it's a disconnect |
877 # ignore this one, it's a disconnect |
879 if self.__sslErrorLock: |
878 if self.__sslErrorLock: |
880 self.networkWidget.addErrorMessage( |
879 self.networkWidget.addErrorMessage( |
881 self.tr("SSL Error"), |
880 self.tr("SSL Error"), |
882 self.tr( |
881 self.tr( |
883 """Connection to server {0} (port {1}) lost while""" |
882 """Connection to server {0} (port {1}) lost while""" |
884 """ waiting for user response to an SSL error.""") |
883 """ waiting for user response to an SSL error.""" |
885 .format(self.__server.getName(), self.__server.getPort())) |
884 ).format(self.__server.getName(), self.__server.getPort()), |
|
885 ) |
886 self.__connectionState = IrcWidget.ServerDisconnected |
886 self.__connectionState = IrcWidget.ServerDisconnected |
887 elif error == QAbstractSocket.SocketError.HostNotFoundError: |
887 elif error == QAbstractSocket.SocketError.HostNotFoundError: |
888 self.networkWidget.addErrorMessage( |
888 self.networkWidget.addErrorMessage( |
889 self.tr("Socket Error"), |
889 self.tr("Socket Error"), |
890 self.tr( |
890 self.tr( |
891 "The host was not found. Please check the host name" |
891 "The host was not found. Please check the host name" |
892 " and port settings.")) |
892 " and port settings." |
|
893 ), |
|
894 ) |
893 elif error == QAbstractSocket.SocketError.ConnectionRefusedError: |
895 elif error == QAbstractSocket.SocketError.ConnectionRefusedError: |
894 self.networkWidget.addErrorMessage( |
896 self.networkWidget.addErrorMessage( |
895 self.tr("Socket Error"), |
897 self.tr("Socket Error"), |
896 self.tr( |
898 self.tr( |
897 "The connection was refused by the peer. Please check the" |
899 "The connection was refused by the peer. Please check the" |
898 " host name and port settings.")) |
900 " host name and port settings." |
|
901 ), |
|
902 ) |
899 elif error == QAbstractSocket.SocketError.SslHandshakeFailedError: |
903 elif error == QAbstractSocket.SocketError.SslHandshakeFailedError: |
900 self.networkWidget.addErrorMessage( |
904 self.networkWidget.addErrorMessage( |
901 self.tr("Socket Error"), |
905 self.tr("Socket Error"), self.tr("The SSL handshake failed.") |
902 self.tr("The SSL handshake failed.")) |
906 ) |
903 else: |
907 else: |
904 if self.__socket: |
908 if self.__socket: |
905 self.networkWidget.addErrorMessage( |
909 self.networkWidget.addErrorMessage( |
906 self.tr("Socket Error"), |
910 self.tr("Socket Error"), |
907 self.tr( |
911 self.tr("The following network error occurred:<br/>{0}").format( |
908 "The following network error occurred:<br/>{0}") |
912 self.__socket.errorString() |
909 .format(self.__socket.errorString())) |
913 ), |
|
914 ) |
910 else: |
915 else: |
911 self.networkWidget.addErrorMessage( |
916 self.networkWidget.addErrorMessage( |
912 self.tr("Socket Error"), |
917 self.tr("Socket Error"), self.tr("A network error occurred.") |
913 self.tr("A network error occurred.")) |
918 ) |
914 |
919 |
915 def __sslErrors(self, errors): |
920 def __sslErrors(self, errors): |
916 """ |
921 """ |
917 Private slot to handle SSL errors. |
922 Private slot to handle SSL errors. |
918 |
923 |
919 @param errors list of SSL errors (list of QSslError) |
924 @param errors list of SSL errors (list of QSslError) |
920 """ |
925 """ |
921 ignored, defaultChanged = self.__sslErrorHandler.sslErrors( |
926 ignored, defaultChanged = self.__sslErrorHandler.sslErrors( |
922 errors, self.__server.getName(), self.__server.getPort()) |
927 errors, self.__server.getName(), self.__server.getPort() |
|
928 ) |
923 if ignored == EricSslErrorState.NOT_IGNORED: |
929 if ignored == EricSslErrorState.NOT_IGNORED: |
924 self.networkWidget.addErrorMessage( |
930 self.networkWidget.addErrorMessage( |
925 self.tr("SSL Error"), |
931 self.tr("SSL Error"), |
926 self.tr( |
932 self.tr( |
927 """Could not connect to {0} (port {1}) using an SSL""" |
933 """Could not connect to {0} (port {1}) using an SSL""" |
928 """ encrypted connection. Either the server does not""" |
934 """ encrypted connection. Either the server does not""" |
929 """ support SSL (did you use the correct port?) or""" |
935 """ support SSL (did you use the correct port?) or""" |
930 """ you rejected the certificate.""") |
936 """ you rejected the certificate.""" |
931 .format(self.__server.getName(), self.__server.getPort())) |
937 ).format(self.__server.getName(), self.__server.getPort()), |
|
938 ) |
932 self.__socket.close() |
939 self.__socket.close() |
933 else: |
940 else: |
934 if defaultChanged: |
941 if defaultChanged: |
935 self.__socket.setSslConfiguration( |
942 self.__socket.setSslConfiguration( |
936 QSslConfiguration.defaultConfiguration()) |
943 QSslConfiguration.defaultConfiguration() |
|
944 ) |
937 if ignored == EricSslErrorState.USER_IGNORED: |
945 if ignored == EricSslErrorState.USER_IGNORED: |
938 self.networkWidget.addErrorMessage( |
946 self.networkWidget.addErrorMessage( |
939 self.tr("SSL Error"), |
947 self.tr("SSL Error"), |
940 self.tr( |
948 self.tr( |
941 """The SSL certificate for the server {0} (port {1})""" |
949 """The SSL certificate for the server {0} (port {1})""" |
942 """ failed the authenticity check. SSL errors""" |
950 """ failed the authenticity check. SSL errors""" |
943 """ were accepted by you.""") |
951 """ were accepted by you.""" |
944 .format(self.__server.getName(), self.__server.getPort())) |
952 ).format(self.__server.getName(), self.__server.getPort()), |
|
953 ) |
945 if self.__connectionState == IrcWidget.ServerConnecting: |
954 if self.__connectionState == IrcWidget.ServerConnecting: |
946 self.__socket.ignoreSslErrors() |
955 self.__socket.ignoreSslErrors() |
947 |
956 |
948 def __setUserPrivilegePrefix(self, prefix1, prefix2): |
957 def __setUserPrivilegePrefix(self, prefix1, prefix2): |
949 """ |
958 """ |
950 Private method to set the user privilege prefix. |
959 Private method to set the user privilege prefix. |
951 |
960 |
952 @param prefix1 first part of the prefix (string) |
961 @param prefix1 first part of the prefix (string) |
953 @param prefix2 indictors the first part gets mapped to (string) |
962 @param prefix2 indictors the first part gets mapped to (string) |
954 """ |
963 """ |
955 # PREFIX=(ov)@+ |
964 # PREFIX=(ov)@+ |
956 # o = @ -> @ircbot , channel operator |
965 # o = @ -> @ircbot , channel operator |
957 # v = + -> +userName , voice operator |
966 # v = + -> +userName , voice operator |
958 for i in range(len(prefix1)): |
967 for i in range(len(prefix1)): |
959 self.__userPrefix["+" + prefix1[i]] = prefix2[i] |
968 self.__userPrefix["+" + prefix1[i]] = prefix2[i] |
960 self.__userPrefix["-" + prefix1[i]] = "" |
969 self.__userPrefix["-" + prefix1[i]] = "" |
961 |
970 |
962 def __ping(self, match): |
971 def __ping(self, match): |
963 """ |
972 """ |
964 Private method to handle a PING message. |
973 Private method to handle a PING message. |
965 |
974 |
966 @param match reference to the match object |
975 @param match reference to the match object |
967 @return flag indicating, if the message was handled (boolean) |
976 @return flag indicating, if the message was handled (boolean) |
968 """ |
977 """ |
969 self.__send("PONG " + match.group(1)) |
978 self.__send("PONG " + match.group(1)) |
970 return True |
979 return True |
971 |
980 |
972 def __handleCtcp(self, match): |
981 def __handleCtcp(self, match): |
973 """ |
982 """ |
974 Private method to handle a CTCP command. |
983 Private method to handle a CTCP command. |
975 |
984 |
976 @param match reference to the match object |
985 @param match reference to the match object |
977 @return flag indicating, if the message was handled (boolean) |
986 @return flag indicating, if the message was handled (boolean) |
978 """ |
987 """ |
979 # group(1) sender user name |
988 # group(1) sender user name |
980 # group(2) sender user@host |
989 # group(2) sender user@host |
994 vers = " " + Version |
1003 vers = " " + Version |
995 msg = "Eric IRC client{0}, {1}".format(vers, Copyright) |
1004 msg = "Eric IRC client{0}, {1}".format(vers, Copyright) |
996 self.networkWidget.addServerMessage( |
1005 self.networkWidget.addServerMessage( |
997 self.tr("CTCP"), |
1006 self.tr("CTCP"), |
998 self.tr("Received Version request from {0}.").format( |
1007 self.tr("Received Version request from {0}.").format( |
999 match.group(1))) |
1008 match.group(1) |
|
1009 ), |
|
1010 ) |
1000 self.__sendCtcpReply(match.group(1), "VERSION " + msg) |
1011 self.__sendCtcpReply(match.group(1), "VERSION " + msg) |
1001 elif ctcpRequest == "ping": |
1012 elif ctcpRequest == "ping": |
1002 self.networkWidget.addServerMessage( |
1013 self.networkWidget.addServerMessage( |
1003 self.tr("CTCP"), |
1014 self.tr("CTCP"), |
1004 self.tr( |
1015 self.tr( |
1005 "Received CTCP-PING request from {0}," |
1016 "Received CTCP-PING request from {0}," " sending answer." |
1006 " sending answer.").format(match.group(1))) |
1017 ).format(match.group(1)), |
1007 self.__sendCtcpReply( |
1018 ) |
1008 match.group(1), "PING {0}".format(ctcpArg)) |
1019 self.__sendCtcpReply(match.group(1), "PING {0}".format(ctcpArg)) |
1009 elif ctcpRequest == "clientinfo": |
1020 elif ctcpRequest == "clientinfo": |
1010 self.networkWidget.addServerMessage( |
1021 self.networkWidget.addServerMessage( |
1011 self.tr("CTCP"), |
1022 self.tr("CTCP"), |
1012 self.tr( |
1023 self.tr( |
1013 "Received CTCP-CLIENTINFO request from {0}," |
1024 "Received CTCP-CLIENTINFO request from {0}," " sending answer." |
1014 " sending answer.").format(match.group(1))) |
1025 ).format(match.group(1)), |
|
1026 ) |
1015 self.__sendCtcpReply( |
1027 self.__sendCtcpReply( |
1016 match.group(1), |
1028 match.group(1), "CLIENTINFO CLIENTINFO PING VERSION" |
1017 "CLIENTINFO CLIENTINFO PING VERSION") |
1029 ) |
1018 else: |
1030 else: |
1019 self.networkWidget.addServerMessage( |
1031 self.networkWidget.addServerMessage( |
1020 self.tr("CTCP"), |
1032 self.tr("CTCP"), |
1021 self.tr( |
1033 self.tr("Received unknown CTCP-{0} request from {1}.").format( |
1022 "Received unknown CTCP-{0} request from {1}.") |
1034 ctcpRequest, match.group(1) |
1023 .format(ctcpRequest, match.group(1))) |
1035 ), |
|
1036 ) |
1024 return True |
1037 return True |
1025 |
1038 |
1026 return False |
1039 return False |
1027 |
1040 |
1028 def __updateUsersCount(self): |
1041 def __updateUsersCount(self): |
1029 """ |
1042 """ |
1030 Private method to update the users count on the channel tabs. |
1043 Private method to update the users count on the channel tabs. |
1031 """ |
1044 """ |
1032 for channel in self.__channelList: |
1045 for channel in self.__channelList: |
1033 index = self.channelsWidget.indexOf(channel) |
1046 index = self.channelsWidget.indexOf(channel) |
1034 self.channelsWidget.setTabText( |
1047 self.channelsWidget.setTabText( |
1035 index, |
1048 index, |
1036 self.tr("{0} ({1})", "channel name, users count").format( |
1049 self.tr("{0} ({1})", "channel name, users count").format( |
1037 channel.name(), channel.getUsersCount())) |
1050 channel.name(), channel.getUsersCount() |
1038 |
1051 ), |
|
1052 ) |
|
1053 |
1039 def __handleNickInUseLogin(self): |
1054 def __handleNickInUseLogin(self): |
1040 """ |
1055 """ |
1041 Private method to handle a 443 server error at login. |
1056 Private method to handle a 443 server error at login. |
1042 """ |
1057 """ |
1043 self.__nickIndex += 1 |
1058 self.__nickIndex += 1 |
1044 try: |
1059 try: |
1045 identity = self.__ircNetworkManager.getIdentity( |
1060 identity = self.__ircNetworkManager.getIdentity(self.__identityName) |
1046 self.__identityName) |
|
1047 if identity: |
1061 if identity: |
1048 nick = identity.getNickNames()[self.__nickIndex] |
1062 nick = identity.getNickNames()[self.__nickIndex] |
1049 self.__nickName = nick |
1063 self.__nickName = nick |
1050 else: |
1064 else: |
1051 self.__connectNetwork("", False, True) |
1065 self.__connectNetwork("", False, True) |
1055 except IndexError: |
1069 except IndexError: |
1056 self.networkWidget.addServerMessage( |
1070 self.networkWidget.addServerMessage( |
1057 self.tr("Critical"), |
1071 self.tr("Critical"), |
1058 self.tr( |
1072 self.tr( |
1059 "No nickname acceptable to the server configured" |
1073 "No nickname acceptable to the server configured" |
1060 " for <b>{0}</b>. Disconnecting...") |
1074 " for <b>{0}</b>. Disconnecting..." |
1061 .format(self.__userName), |
1075 ).format(self.__userName), |
1062 filterMsg=False) |
1076 filterMsg=False, |
|
1077 ) |
1063 self.__connectNetwork("", False, True) |
1078 self.__connectNetwork("", False, True) |
1064 self.__nickName = "" |
1079 self.__nickName = "" |
1065 self.__nickIndex = -1 |
1080 self.__nickIndex = -1 |
1066 return |
1081 return |
1067 |
1082 |
1068 self.networkWidget.setNickName(nick) |
1083 self.networkWidget.setNickName(nick) |
1069 self.__send("NICK " + nick) |
1084 self.__send("NICK " + nick) |
1070 |
1085 |
1071 def __handleNickInUse(self): |
1086 def __handleNickInUse(self): |
1072 """ |
1087 """ |
1073 Private method to handle a 443 server error. |
1088 Private method to handle a 443 server error. |
1074 """ |
1089 """ |
1075 self.networkWidget.addServerMessage( |
1090 self.networkWidget.addServerMessage( |
1076 self.tr("Critical"), |
1091 self.tr("Critical"), self.tr("The given nickname is already in use.") |
1077 self.tr("The given nickname is already in use.")) |
1092 ) |
1078 |
1093 |
1079 def __changeNick(self, nick): |
1094 def __changeNick(self, nick): |
1080 """ |
1095 """ |
1081 Private slot to use a new nick name. |
1096 Private slot to use a new nick name. |
1082 |
1097 |
1083 @param nick nick name to use (str) |
1098 @param nick nick name to use (str) |
1084 """ |
1099 """ |
1085 if nick and nick != self.__nickName: |
1100 if nick and nick != self.__nickName: |
1086 self.__send("NICK " + nick) |
1101 self.__send("NICK " + nick) |
1087 |
1102 |
1088 def __setChannelTypePrefixes(self, prefixes): |
1103 def __setChannelTypePrefixes(self, prefixes): |
1089 """ |
1104 """ |
1090 Private method to set the channel type prefixes. |
1105 Private method to set the channel type prefixes. |
1091 |
1106 |
1092 @param prefixes channel prefix characters (string) |
1107 @param prefixes channel prefix characters (string) |
1093 """ |
1108 """ |
1094 self.__channelTypePrefixes = prefixes |
1109 self.__channelTypePrefixes = prefixes |
1095 |
1110 |
1096 def isChannelName(self, name): |
1111 def isChannelName(self, name): |
1097 """ |
1112 """ |
1098 Public method to check, if the given name is a channel name. |
1113 Public method to check, if the given name is a channel name. |
1099 |
1114 |
1100 @param name name to check (string) |
1115 @param name name to check (string) |
1101 @return flag indicating a channel name (boolean) |
1116 @return flag indicating a channel name (boolean) |
1102 """ |
1117 """ |
1103 if not name: |
1118 if not name: |
1104 return False |
1119 return False |
1105 |
1120 |
1106 if self.__channelTypePrefixes: |
1121 if self.__channelTypePrefixes: |
1107 return name[0] in self.__channelTypePrefixes |
1122 return name[0] in self.__channelTypePrefixes |
1108 else: |
1123 else: |
1109 return name[0] in "#&" |
1124 return name[0] in "#&" |
1110 |
1125 |
1111 def __away(self, isAway): |
1126 def __away(self, isAway): |
1112 """ |
1127 """ |
1113 Private slot handling the change of the away state. |
1128 Private slot handling the change of the away state. |
1114 |
1129 |
1115 @param isAway flag indicating the current away state (boolean) |
1130 @param isAway flag indicating the current away state (boolean) |
1116 """ |
1131 """ |
1117 if isAway and self.__identityName: |
1132 if isAway and self.__identityName: |
1118 identity = self.__ircNetworkManager.getIdentity( |
1133 identity = self.__ircNetworkManager.getIdentity(self.__identityName) |
1119 self.__identityName) |
|
1120 if identity and identity.rememberAwayPosition(): |
1134 if identity and identity.rememberAwayPosition(): |
1121 for channel in self.__channelList: |
1135 for channel in self.__channelList: |
1122 channel.setMarkerLine() |
1136 channel.setMarkerLine() |