| 268 | | |
| 269 | | from common.xmpp import Message as XmppMessage |
| 270 | | |
| 271 | | try: |
| 272 | | import otr, otr_windows |
| 273 | | gajim.otr_module = otr |
| 274 | | gajim.otr_windows = otr_windows |
| 275 | | except ImportError: |
| 276 | | gajim.otr_module = None |
| 277 | | gajim.otr_windows = None |
| 278 | | |
| 279 | | def add_appdata(data, context): |
| 280 | | account = data |
| 281 | | context.app_data = otr_windows.ContactOtrSMPWindow( |
| 282 | | unicode(context.username), account) |
| 283 | | |
| 284 | | gajim.otr_add_appdata = add_appdata |
| 285 | | |
| 286 | | def otr_dialog_destroy(widget, *args, **kwargs): |
| 287 | | widget.destroy() |
| 288 | | |
| 289 | | class OtrlMessageAppOps: |
| 290 | | def gajim_log(self, msg, account, fjid, no_print=False): |
| 291 | | if not isinstance(fjid, unicode): |
| 292 | | fjid = unicode(fjid) |
| 293 | | if not isinstance(account, unicode): |
| 294 | | account = unicode(account) |
| 295 | | resource=gajim.get_resource_from_jid(fjid) |
| 296 | | tim = time.localtime() |
| 297 | | |
| 298 | | if not no_print: |
| 299 | | ctrl = self.get_control(fjid, account) |
| 300 | | if ctrl: |
| 301 | | ctrl.print_conversation_line(u'[OTR] %s' % \ |
| 302 | | msg, 'status', '', None) |
| 303 | | id = gajim.logger.write('chat_msg_recv', fjid, |
| 304 | | message='[OTR: %s]' % msg, tim=tim) |
| 305 | | # gajim.logger.write() only marks a message as unread |
| 306 | | # (and so only returns an id) when fjid is a real contact |
| 307 | | # (NOT if it's a GC private chat) |
| 308 | | if id: |
| 309 | | gajim.logger.set_read_messages([id]) |
| 310 | | |
| 311 | | def get_control(self, fjid, account): |
| 312 | | # first try to get the window with the full jid |
| 313 | | ctrls = gajim.interface.msg_win_mgr.get_chat_controls(fjid, account) |
| 314 | | if ctrls: |
| 315 | | # got one, be happy |
| 316 | | return ctrls[0] |
| 317 | | |
| 318 | | # otherwise try without the resource |
| 319 | | ctrls = gajim.interface.msg_win_mgr.get_chat_controls( |
| 320 | | gajim.get_jid_without_resource(fjid), account) |
| 321 | | # but only use it when it is not a GC window |
| 322 | | if ctrls and ctrls[0].TYPE_ID == message_control.TYPE_CHAT: |
| 323 | | return ctrls[0] |
| 324 | | |
| 325 | | def policy(self, opdata=None, context=None): |
| 326 | | policy = gajim.config.get_per('contacts', context.username, |
| 327 | | "otr_flags") |
| 328 | | if policy <= 0: |
| 329 | | policy = gajim.config.get_per('contacts', |
| 330 | | gajim.get_jid_without_resource( |
| 331 | | context.username), 'otr_flags') |
| 332 | | if policy <= 0: |
| 333 | | policy = gajim.config.get_per('accounts', |
| 334 | | opdata['account'], 'otr_flags') |
| 335 | | return policy |
| 336 | | |
| 337 | | def create_privkey(self, opdata='', accountname='', protocol=''): |
| 338 | | dialog = gtk.Dialog( |
| 339 | | title = _('Generating...'), |
| 340 | | parent = gajim.interface.roster.window, |
| 341 | | flags = gtk.DIALOG_MODAL, |
| 342 | | buttons = (gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)) |
| 343 | | permlabel = gtk.Label(_('Generating a private key for %s...') \ |
| 344 | | % accountname) |
| 345 | | permlabel.set_padding(20, 20) |
| 346 | | dialog.set_response_sensitive(gtk.RESPONSE_CLOSE, False) |
| 347 | | dialog.connect('destroy', otr_dialog_destroy) |
| 348 | | dialog.connect('response', otr_dialog_destroy) |
| 349 | | dialog.vbox.pack_start(permlabel) |
| 350 | | dialog.get_root_window().raise_() |
| 351 | | dialog.show_all() |
| 352 | | dialog.map() |
| 353 | | for c in dialog.get_children(): |
| 354 | | c.show_now() |
| 355 | | c.map() |
| 356 | | |
| 357 | | while gtk.events_pending(): |
| 358 | | gtk.main_iteration(block = False) |
| 359 | | |
| 360 | | otr.otrl_privkey_generate( |
| 361 | | gajim.connections[opdata['account']].otr_userstates, |
| 362 | | os.path.join(gajimpaths.root, |
| 363 | | '%s.key' % opdata['account']).encode(), |
| 364 | | accountname, gajim.OTR_PROTO) |
| 365 | | permlabel.set_text(_('Generating a private key for %s...\n' \ |
| 366 | | 'done.') % accountname) |
| 367 | | dialog.set_response_sensitive(gtk.RESPONSE_CLOSE, True) |
| 368 | | |
| 369 | | def is_logged_in(self, opdata={}, accountname='', protocol='', |
| 370 | | recipient=""): |
| 371 | | contact = gajim.contacts.get_contact_from_full_jid( |
| 372 | | opdata['account'], recipient) |
| 373 | | if contact: |
| 374 | | return contact.show \ |
| 375 | | in ['dnd', 'xa', 'chat', 'online', 'away', |
| 376 | | 'invisible'] |
| 377 | | return 0 |
| 378 | | |
| 379 | | def inject_message(self, opdata=None, accountname='', protocol='', |
| 380 | | recipient='', message=''): |
| 381 | | msg_type = otr.otrl_proto_message_type(message) |
| 382 | | |
| 383 | | if 'kwargs' not in opdata or 'urgent' in opdata: |
| 384 | | # don't use send_message here to have the message |
| 385 | | # sent immediatly. This results in being able to |
| 386 | | # disconnect from OTR sessions before quitting |
| 387 | | stanza = XmppMessage(to = recipient, |
| 388 | | body = message, typ='chat') |
| 389 | | gajim.connections[opdata['account']].connection. \ |
| 390 | | send(stanza, now = True) |
| 391 | | return |
| 392 | | |
| 393 | | if msg_type == otr.OTRL_MSGTYPE_QUERY: |
| 394 | | # split away XHTML-contaminated explanatory message |
| 395 | | message = unicode(message.splitlines()[0]) |
| 396 | | message += _(u'\nThis user has requested an ' \ |
| 397 | | 'Off-the-Record private conversation. ' \ |
| 398 | | 'However, you do not have a plugin to ' \ |
| 399 | | 'support that.\n' \ |
| 400 | | 'See http://otr.cypherpunks.ca/ for more ' \ |
| 401 | | 'information.') |
| 402 | | |
| 403 | | gajim.connections[opdata['account']].connection.send( |
| 404 | | common.xmpp.Message(to = recipient, |
| 405 | | body = message, typ = 'chat')) |
| 406 | | return |
| 407 | | |
| 408 | | gajim.connections[opdata['account']].send_message(recipient, |
| 409 | | message, **opdata['kwargs']) |
| 410 | | |
| 411 | | def notify(sef, opdata=None, username='', **kwargs): |
| 412 | | self.gajim_log('Notify: ' + str(kwargs), opdata['account'], |
| 413 | | username) |
| 414 | | |
| 415 | | def display_otr_message(self, opdata=None, username="", msg="", **kwargs): |
| 416 | | self.gajim_log('OTR Message: ' + msg, opdata['account'], |
| 417 | | username) |
| 418 | | return 0 |
| 419 | | |
| 420 | | def update_context_list(self, **kwargs): |
| 421 | | # FIXME stub FIXME # |
| 422 | | pass |
| 423 | | |
| 424 | | def protocol_name(self, opdata=None, protocol=""): |
| 425 | | return 'XMPP' |
| 426 | | |
| 427 | | def new_fingerprint(self, opdata=None, username='', fingerprint='', |
| 428 | | **kwargs): |
| 429 | | self.gajim_log('New fingerprint for %s: %s' % (username, |
| 430 | | otr.otrl_privkey_hash_to_human(fingerprint)), |
| 431 | | opdata['account'], username) |
| 432 | | |
| 433 | | def write_fingerprints(self, opdata=''): |
| 434 | | otr.otrl_privkey_write_fingerprints( |
| 435 | | gajim.connections[opdata['account']].otr_userstates, |
| 436 | | os.path.join(gajimpaths.root, '%s.fpr' % \ |
| 437 | | opdata['account']).encode()) |
| 438 | | |
| 439 | | def gone_secure(self, opdata='', context=None): |
| 440 | | trust = context.active_fingerprint.trust \ |
| 441 | | and 'verified' or 'unverified' |
| 442 | | self.gajim_log('%s secured OTR connection started' % trust, |
| 443 | | opdata['account'], context.username, no_print = True) |
| 444 | | |
| 445 | | ctrl = self.get_control(context.username, opdata['account']) |
| 446 | | if ctrl: |
| 447 | | ctrl.update_otr(True) |
| 448 | | |
| 449 | | def gone_insecure(self, opdata='', context=None): |
| 450 | | self.gajim_log('Private conversation with %s lost.', |
| 451 | | opdata['account'], context.username) |
| 452 | | |
| 453 | | ctrl = self.get_control(context.username, opdata['account']) |
| 454 | | if ctrl: |
| 455 | | ctrl.update_otr(True) |
| 456 | | |
| 457 | | def still_secure(self, opdata=None, context=None, is_reply=0): |
| 458 | | ctrl = self.get_control(context.username, opdata['account']) |
| 459 | | if ctrl: |
| 460 | | ctrl.update_otr(True) |
| 461 | | |
| 462 | | self.gajim_log('OTR connection was refreshed', |
| 463 | | opdata['account'], context.username) |
| 464 | | |
| 465 | | def log_message(self, opdata=None, message=''): |
| 466 | | gajim.log.debug(message) |
| 467 | | |
| 468 | | def max_message_size(self, **kwargs): |
| 469 | | return 0 |
| 470 | | |
| 471 | | def account_name(self, opdata=None, account='', protocol=''): |
| 472 | | return gajim.get_name_from_jid(opdata['account'], |
| 473 | | unicode(account)) |
| 474 | | |
| 475 | | gajim.otr_ui_ops = OtrlMessageAppOps() |