image.py 5.71 KB
Newer Older
Dicson's avatar
Dicson committed
1
2
# -*- coding: utf-8 -*-
##
Dicson's avatar
Dicson committed
3
4
5
from gi.repository import Gtk
from gi.repository import Gdk
from gi.repository import GObject
Dicson's avatar
Dicson committed
6
7
import os
import base64
Dicson's avatar
Dicson committed
8
import urllib
Dicson's avatar
Dicson committed
9

Dicson's avatar
Dicson committed
10
import chat_control
Dicson's avatar
Dicson committed
11
12
13
14
from plugins import GajimPlugin
from plugins.helpers import log_calls
from dialogs import ImageChooserDialog, ErrorDialog

Dicson's avatar
Dicson committed
15
16
NS_XHTML_IM = 'http://jabber.org/protocol/xhtml-im'             # XEP-0071

Dicson's avatar
Dicson committed
17
18
19
20

class ImagePlugin(GajimPlugin):
    @log_calls('ImagePlugin')
    def init(self):
Dicson's avatar
Dicson committed
21
22
23
24
25
        self.description = _('This plugin is designed to send '
            'a small(0 - 40 kb) graphic image to your contact.\n'
            'Client on the other side must support XEP-0071: XHTML-IM'
            ' and maintain the scheme data: URI.\n'
            'Psi+ and Jabbim supported this.')
Dicson's avatar
Dicson committed
26
27
28
29
30
31
32
        self.config_dialog = None  # ImagePluginConfigDialog(self)
        self.controls = []
        self.gui_extension_points = {
            'chat_control_base': (self.connect_with_chat_control,
                self.disconnect_from_chat_control),
            'chat_control_base_update_toolbar': (self.update_button_state,
                None)}
33
        self.first_run = True
Dicson's avatar
Dicson committed
34
35

    @log_calls('ImagePlugin')
Dicson's avatar
Dicson committed
36
37
38
39
40
41
    def connect_with_chat_control(self, control):
        if not isinstance(control, chat_control.ChatControl):
            return
        self.chat_control = control
        base = Base(self, self.chat_control)
        self.controls.append(base)
Dicson's avatar
Dicson committed
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

    @log_calls('ImagePlugin')
    def disconnect_from_chat_control(self, chat_control):
        for control in self.controls:
            control.disconnect_from_chat_control()
        self.controls = []

    @log_calls('ImagePlugin')
    def update_button_state(self, chat_control):
        for base in self.controls:
            if base.chat_control == chat_control:
                is_support_xhtml = chat_control.contact.supports(NS_XHTML_IM)
                base.button.set_sensitive(is_support_xhtml and not \
                    chat_control.gpg_is_active)
                if not is_support_xhtml:
                    text = _('This contact does not support XHTML_IM')
                else:
                    text = _('Send image')
                base.button.set_tooltip_text(text)


class Base(object):
    def __init__(self, plugin, chat_control):
Dicson's avatar
Dicson committed
65
66
67
        ## ALT + L
        self.id_ = chat_control.msg_textview.connect('key_press_event',
            self._on_message_textview_key_press_event)
Dicson's avatar
Dicson committed
68
69
70
        self.plugin = plugin
        self.chat_control = chat_control
        actions_hbox = chat_control.xml.get_object('actions_hbox')
Dicson's avatar
Dicson committed
71
72
        self.button = Gtk.Button(label=None, stock=None, use_underline=True)
        self.button.set_property('relief', Gtk.ReliefStyle.NONE)
Dicson's avatar
Dicson committed
73
        self.button.set_property('can-focus', False)
Dicson's avatar
Dicson committed
74
75
        img = Gtk.Image()
        img.set_from_stock('gtk-orientation-portrait', Gtk.IconSize.MENU)
Dicson's avatar
Dicson committed
76
        self.button.set_image(img)
Dicson's avatar
Dicson committed
77
        self.button.set_tooltip_text('Send image')
Dicson's avatar
Dicson committed
78
        send_button = chat_control.xml.get_object('send_button')
Dicson's avatar
Dicson committed
79
80
81
        actions_hbox.pack_start(self.button, False, False , 0)
        actions_hbox.reorder_child(self.button,
            len(actions_hbox.get_children()) - 3)
Dicson's avatar
Dicson committed
82
        id_ = self.button.connect('clicked', self.on_image_button_clicked)
Dicson's avatar
Dicson committed
83
84
        self.chat_control.handlers[id_] = self.button
        self.chat_control.handlers[self.id_] = chat_control.msg_textview
Dicson's avatar
Dicson committed
85
86
        self.button.show()

Dicson's avatar
Dicson committed
87
88
    def _on_message_textview_key_press_event(self, widget, event):
        if event.get_state() & Gdk.ModifierType.MOD1_MASK and \
Dicson's avatar
Dicson committed
89
            event.keyval == Gdk.KEY_l:
Dicson's avatar
Dicson committed
90
91
92
93
94
95
96
97
            if not self.chat_control.contact.supports(NS_XHTML_IM):
                from dialogs import WarningDialog
                WarningDialog('Warning',
                    _('This contact does not support XHTML_IM'),
                    self.chat_control.parent_win.window)
                return True
            self.on_image_button_clicked(widget)
            return True
98

Dicson's avatar
Dicson committed
99
100
101
102
103
104
105
106
107
108
109
110
111
112
    def on_image_button_clicked(self, widget):
        def on_ok(widget, path_to_file):
            filesize = os.path.getsize(path_to_file)  # in bytes
            invalid_file = False
            msg = ''
            if os.path.isfile(path_to_file):
                stat = os.stat(path_to_file)
                if stat[6] == 0:
                    invalid_file = True
                    msg = _('File is empty')
            else:
                invalid_file = True
                msg = _('File does not exist')
            if filesize < 60000:
Dicson's avatar
Dicson committed
113
114
115
                file_ = open(path_to_file, "rb")
                img = urllib.parse.quote(base64.standard_b64encode(
                    file_.read()), '')
Dicson's avatar
Dicson committed
116
117
118
                if len(img) > 60000:
                    invalid_file = True
                    msg = _('File too big')
Dicson's avatar
Dicson committed
119
                file_.close()
Dicson's avatar
Dicson committed
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
            else:
                invalid_file = True
                msg = _('File too big')
            if invalid_file:
                ErrorDialog(_('Could not load image'), msg)
                return

            dlg.destroy()
            msg = 'HTML image'
            extension = os.path.splitext(os.path.split(path_to_file)[1])[1] \
                .lower()[1:]
            xhtml = ' <img alt="img" src="data:image/%s;base64,%s"/>' % (
                extension, img)
            self.chat_control.send_message(message=msg, xhtml=xhtml)
            self.chat_control.msg_textview.grab_focus()

        dlg = ImageChooserDialog(on_response_ok=on_ok, on_response_cancel=None)

    def disconnect_from_chat_control(self):
        actions_hbox = self.chat_control.xml.get_object('actions_hbox')
        actions_hbox.remove(self.button)
Dicson's avatar
Dicson committed
141
142
143
        if self.chat_control.handlers[self.id_].handler_is_connected(self.id_):
            self.chat_control.handlers[self.id_].disconnect(self.id_)
            del self.chat_control.handlers[self.id_]