def print_special_text(self, special_text, other_tags, graphics=True, iter_=None): if not self.plugin.active: return is_xhtml_link = None text_is_valid_uri = False buffer_ = self.textview.tv.get_buffer() # Detect XHTML-IM link ttt = buffer_.get_tag_table() tags_ = [(ttt.lookup(t) if isinstance(t, str) else t) for t in other_tags] for t in tags_: is_xhtml_link = getattr(t, 'href', None) if is_xhtml_link: break # Check if we accept this as an uri schemes = gajim.config.get('uri_schemes').split() for scheme in schemes: if special_text.startswith(scheme): text_is_valid_uri = True if special_text.startswith('www.') or special_text.startswith('ftp.') \ or text_is_valid_uri and not is_xhtml_link: if len(special_text) < self.plugin.config['IN_MAX_CHARS']: return end_iter = buffer_.get_end_iter() mark = buffer_.create_mark(None, end_iter, True) gajim.thread_interface(self.insert_hyperlink, [mark, special_text, ttt]) self.textview.plugin_modified = True
def print_special_text(self, tv, special_text, other_tags, graphics=True, iter_=None): conv_textview = tv textview = tv.tv # geo:48.2057365,16.3435941 if not special_text.startswith('geo:'): return buffer_ = textview.get_buffer() if not iter_: iter_ = buffer_.get_end_iter() # Show URL, until image is loaded (if ever) ttt = buffer_.get_tag_table() repl_start = buffer_.create_mark(None, iter_, True) buffer_.insert_with_tags(iter_, special_text, *[(ttt.lookup(t) if isinstance(t, str) else t) for t in ["url"]]) repl_end = buffer_.create_mark(None, iter_, True) zoom = 17 size = 200 color = 'blue' coordinates = special_text.split(':')[1] lat = coordinates.split(',')[0] lon = coordinates.split(',')[1] if not (len(lat) == 10 and len(lon) == 10): return filename = coordinates.replace(',', '_').replace('.', '-') filepath = os.path.join(self.thumbpath, filename) url = 'https://maps.googleapis.com/maps/api/staticmap?center={}' \ '&zoom={}&size={}x{}&markers=color:{}' \ '|label:S|{}'.format(coordinates, zoom, size, size, color, coordinates) weburl = 'https://www.google.at/maps/place/{}'.format(coordinates) log.debug(url) if os.path.exists(filepath): gajim.thread_interface( self.load_thumbnail, [filepath], self.updatechat, [weburl, repl_start, repl_end, textview]) else: gajim.thread_interface( self.download, [url, filepath], self.updatechat, [weburl, repl_start, repl_end, textview]) # Don't print the URL in the message window (in the calling function) conv_textview.plugin_modified = True
def print_special_text(self, special_text, other_tags, graphics=True, iter_=None): # remove qip bbcode special_text = special_text.rsplit('[/img]')[0] if special_text.startswith('www.'): special_text = 'http://' + special_text if special_text.startswith('ftp.'): special_text = 'ftp://' + special_text parts = urlparse(special_text) if parts.scheme not in ["https", "http", "ftp", "ftps"] or \ not parts.netloc: log.info("Not accepting URL for image preview: %s" % special_text) return buffer_ = self.textview.tv.get_buffer() if not iter_: iter_ = buffer_.get_end_iter() # Detect XHTML-IM link ttt = buffer_.get_tag_table() tags_ = [(ttt.lookup(t) if isinstance(t, str) else t) for t in other_tags] for t in tags_: is_xhtml_link = getattr(t, 'href', None) if is_xhtml_link: break # Show URL, until image is loaded (if ever) repl_start = buffer_.create_mark(None, iter_, True) buffer_.insert_with_tags(iter_, special_text, \ *[(ttt.lookup(t) if isinstance(t, str) else t) for t in ["url"]]) repl_end = buffer_.create_mark(None, iter_, True) # First get the http head request with does not fetch data, just headers gajim.thread_interface(self._get_http_head, [self.textview.account, special_text], self._check_mime_size, [special_text, repl_start, repl_end]) # Don't print the URL in the message window (in the calling function) self.textview.plugin_modified = True
def _process_img(self, attrs, loaded=None): '''Process a img tag. ''' mem = '' update = False pixbuf = None replace_mark = None replace_tags = None try: if attrs['src'].startswith('data:image/'): # The "data" URL scheme http://tools.ietf.org/html/rfc2397 import base64 img = attrs['src'].split(',')[1] mem = base64.standard_b64decode( urllib.parse.unquote(img).encode('utf-8')) elif loaded is not None: (mem, alt, replace_mark, replace_tags) = loaded update = True else: if self.conv_textview: img_mark = self.textbuf.create_mark(None, self.iter, True) gajim.thread_interface( helpers.download_image, [self.conv_textview.account, attrs], self._update_img, [attrs, img_mark, self._get_style_tags()]) alt = attrs.get('alt', '') if alt: alt += '\n' alt += _('Loading') pixbuf = get_icon_pixmap('gtk-no') if mem: # Caveat: GdkPixbuf is known not to be safe to load # images from network... this program is now potentially # hackable ;) loader = GdkPixbuf.PixbufLoader() dims = [0, 0] def height_cb(length): dims[1] = length def width_cb(length): dims[0] = length # process width and height attributes w = attrs.get('width') h = attrs.get('height') # override with width and height styles for attr, val in style_iter(attrs.get('style', '')): if attr == 'width': w = val elif attr == 'height': h = val if w: self._parse_length(w, False, False, 1, 1000, width_cb) if h: self._parse_length(h, False, False, 1, 1000, height_cb) def set_size(pixbuf, w, h, dims): """ FIXME: Floats should be relative to the whole textview, and resize with it. This needs new pifbufs for every resize, GdkPixbuf.Pixbuf.scale_simple or similar. """ if isinstance(dims[0], float): dims[0] = int(dims[0] * w) elif not dims[0]: dims[0] = w if isinstance(dims[1], float): dims[1] = int(dims[1] * h) if not dims[1]: dims[1] = h loader.set_size(*dims) if w or h: loader.connect('size-prepared', set_size, dims) loader.write(mem) loader.close() pixbuf = loader.get_pixbuf() alt = attrs.get('alt', '') working_iter = self.iter if replace_mark is not None: working_iter = self.textbuf.get_iter_at_mark(replace_mark) next_iter = working_iter.copy() next_iter.forward_char() self.textbuf.delete(working_iter, next_iter) self.textbuf.delete_mark(replace_mark) if pixbuf is not None: if replace_mark: tags = replace_tags else: tags = self._get_style_tags() if tags: tmpmark = self.textbuf.create_mark(None, working_iter, True) self.textbuf.insert_pixbuf(working_iter, pixbuf) self.starting = False if tags: start = self.textbuf.get_iter_at_mark(tmpmark) for tag in tags: self.textbuf.apply_tag(tag, start, working_iter) self.textbuf.delete_mark(tmpmark) else: self._insert_text('[IMG: %s]' % alt, working_iter) except Exception as ex: log.error('Error loading image ' + str(ex)) pixbuf = None alt = attrs.get('alt', 'Broken image') try: loader.close() except Exception: pass return pixbuf
def print_special_text(self, special_text, other_tags, graphics=True, iter__=None): if gajim.interface.pointim_sharp_slash_re.match(special_text): # insert post num #123456// buffer_, iter_, tag = self.get_iter_and_tag('pointim_sharp_slash') buffer_.insert_with_tags(iter__, special_text, tag) self.last_pointim_num = special_text self.textview.plugin_modified = True return if gajim.interface.pointim_nick_re.match(special_text): # insert pointim nick @nickname//// buffer_, iter_, tag = self.get_iter_and_tag('pointim_nick') mark = buffer_.create_mark(None, iter__, True) nick = special_text[1:].rstrip(':') buffer_.insert_with_tags(iter__, special_text, tag) # insert avatars if not self.plugin.config['SHOW_AVATARS']: self.textview.plugin_modified = True return b_nick = buffer_.get_text(buffer_.get_start_iter(), buffer_.get_iter_at_mark(mark),False) if self.plugin.config['ONLY_AUTHOR_AVATAR'] and not \ special_text.endswith(':') and b_nick[-9:] not in ('Subscribed to ' ): self.textview.plugin_modified = True return if self.plugin.config['ONLY_FIRST_AVATAR']: if b_nick[-9:] not in ('Reply by ', 'message from ', 'ended by ', 'Subscribed to '): if b_nick[-2] != gajim.config.get('after_nickname'): self.textview.plugin_modified = True return elif b_nick[-1] == '\n': self.textview.plugin_modified = True return conn = gajim.connections[self.chat_control.account] if not conn.connected: self.textview.plugin_modified = True return # search id in the db query = "select nick, id from person where nick = :nick" self.plugin.cursor.execute(query, {'nick':nick}) db_item = self.plugin.cursor.fetchone() if db_item: # nick in the db pixbuf = self.get_avatar(db_item[1], nick, True) if not pixbuf: self.textview.plugin_modified = True return end_iter = buffer_.get_iter_at_mark(mark) anchor = buffer_.create_child_anchor(end_iter) img = TextViewImage(anchor, nick) img.set_from_pixbuf(pixbuf) img.show() self.textview.tv.add_child_at_anchor(img, anchor) self.textview.plugin_modified = True return else: # nick not in the db gobject.idle_add(self.get_new_avatar, mark, nick) return if gajim.interface.pointim_pic_re.match(special_text) and \ self.plugin.config['SHOW_PREVIEW']: # show pics preview buffer_, iter_, tag = self.get_iter_and_tag('url') mark = buffer_.create_mark(None, iter_, True) buffer_.insert_with_tags(iter_, special_text, tag) uid = special_text.split('/')[-1] url = "http://i.pointim.com/photos-512/%s" % uid gajim.thread_interface(self.insert_pic_preview, [mark, special_text, url]) self.textview.plugin_modified = True return
def upload_file(stanza): slot = stanza.getTag("slot") if not slot: progress_window.close_dialog() log.error("got unexpected stanza: "+str(stanza)) error = stanza.getTag("error") if error and error.getTag("text"): ErrorDialog(_('Could not request upload slot'), _('Got unexpected response from server: %s') % str(error.getTagData("text")), transient_for=self.chat_control.parent_win.window) else: ErrorDialog(_('Could not request upload slot'), _('Got unexpected response from server (protocol mismatch??)'), transient_for=self.chat_control.parent_win.window) return try: if self.encrypted_upload: key = os.urandom(32) iv = os.urandom(16) data = StreamFileWithProgress(path_to_file, "rb", progress_window.update_progress, self.encrypted_upload, key, iv) else: data = StreamFileWithProgress(path_to_file, "rb", progress_window.update_progress) except: progress_window.close_dialog() ErrorDialog(_('Could not open file'), _('Exception raised while opening file (see error log for more information)'), transient_for=self.chat_control.parent_win.window) raise # fill error log with useful information put = slot.getTag("put") get = slot.getTag("get") if not put or not get: progress_window.close_dialog() log.error("got unexpected stanza: " + str(stanza)) ErrorDialog(_('Could not request upload slot'), _('Got unexpected response from server (protocol mismatch??)'), transient_for=self.chat_control.parent_win.window) return def upload_complete(response_code): if response_code == 0: return # Upload was aborted if response_code >= 200 and response_code < 300: log.info("Upload completed successfully") xhtml = None is_image = mime_type.split('/', 1)[0] == 'image' if (not isinstance(self.chat_control, chat_control.ChatControl) or not self.chat_control.gpg_is_active) and \ self.dialog_type == 'image' and is_image and not self.encrypted_upload: progress_messages.put(_('Calculating (possible) image thumbnail...')) thumb = None quality_steps = (100, 80, 60, 50, 40, 35, 30, 25, 23, 20, 18, 15, 13, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) with open(path_to_file, 'rb') as content_file: thumb = urllib2.quote(base64.standard_b64encode(content_file.read()), '') if thumb and len(thumb) < max_thumbnail_size: quality = 100 log.info("Image small enough (%d bytes), not resampling" % len(thumb)) elif pil_available: log.info("PIL available, using it for image downsampling") try: for quality in quality_steps: thumb = Image.open(path_to_file) thumb.thumbnail((max_thumbnail_dimension, max_thumbnail_dimension), Image.ANTIALIAS) output = BytesIO() thumb.save(output, format='JPEG', quality=quality, optimize=True) thumb = output.getvalue() output.close() thumb = urllib2.quote(base64.standard_b64encode(thumb), '') log.debug("pil thumbnail jpeg quality %d produces an image of size %d..." % (quality, len(thumb))) if len(thumb) < max_thumbnail_size: break except: thumb = None else: thumb = None if not thumb: log.info("PIL not available, using GTK for image downsampling") temp_file = None try: with open(path_to_file, 'rb') as content_file: thumb = content_file.read() loader = gtk.gdk.PixbufLoader() loader.write(thumb) loader.close() pixbuf = loader.get_pixbuf() scaled_pb = self.get_pixbuf_of_size(pixbuf, max_thumbnail_dimension) handle, temp_file = tempfile.mkstemp(suffix='.jpeg', prefix='gajim_httpupload_scaled_tmp', dir=gajim.TMP) log.debug("Saving temporary jpeg image to '%s'..." % temp_file) os.close(handle) for quality in quality_steps: scaled_pb.save(temp_file, "jpeg", {"quality": str(quality)}) with open(temp_file, 'rb') as content_file: thumb = content_file.read() thumb = urllib2.quote(base64.standard_b64encode(thumb), '') log.debug("gtk thumbnail jpeg quality %d produces an image of size %d..." % (quality, len(thumb))) if len(thumb) < max_thumbnail_size: break except: thumb = None finally: if temp_file: os.unlink(temp_file) if thumb: if len(thumb) > max_thumbnail_size: log.info("Couldn't compress image enough, not sending any thumbnail") else: log.info("Using thumbnail jpeg quality %d (image size: %d bytes)" % (quality, len(thumb))) xhtml = '<body><br/><a href="%s"> <img alt="%s" src="data:image/png;base64,%s"/> </a></body>' % \ (get.getData(), get.getData(), thumb) progress_window.close_dialog() id_ = gajim.get_an_id() def add_oob_tag(): pass if self.encrypted_upload: keyAndIv = '#' + binascii.hexlify(iv) + binascii.hexlify(key) self.chat_control.send_message(message=get.getData() + keyAndIv, xhtml=None) else: self.chat_control.send_message(message=get.getData(), xhtml=xhtml) self.chat_control.msg_textview.grab_focus() else: progress_window.close_dialog() log.error("got unexpected http upload response code: " + str(response_code)) ErrorDialog(_('Could not upload file'), _('Got unexpected http response code from server: ') + str(response_code), transient_for=self.chat_control.parent_win.window) def uploader(): progress_messages.put(_('Uploading file via HTTP...')) try: headers = {'User-Agent': 'Gajim %s' % gajim.version, 'Content-Type': mime_type} request = urllib2.Request(put.getData().encode("utf-8"), data=data, headers=headers) request.get_method = lambda: 'PUT' log.debug("opening urllib2 upload request...") transfer = urllib2.urlopen(request, timeout=30) log.debug("urllib2 upload request done, response code: " + str(transfer.getcode())) return transfer.getcode() except UploadAbortedException: log.info("Upload aborted") except: progress_window.close_dialog() ErrorDialog(_('Could not upload file'), _('Got unexpected exception while uploading file (see error log for more information)'), transient_for=self.chat_control.parent_win.window) raise # fill error log with useful information return 0 log.info("Uploading file to '%s'..." % str(put.getData())) log.info("Please download from '%s' later..." % str(get.getData())) gajim.thread_interface(uploader, [], upload_complete)
class Base(object): def __init__(self, plugin, chat_control): self.plugin = plugin self.chat_control = chat_control self.textview = self.chat_control.conv_textview if os.name == 'nt': self.backend = backend else: self.backend = default_backend() def print_special_text(self, special_text, other_tags, graphics=True, iter_=None): # remove qip bbcode special_text = special_text.rsplit('[/img]')[0] if special_text.startswith('www.'): special_text = 'http://' + special_text if special_text.startswith('ftp.'): special_text = 'ftp://' + special_text parts = urlparse(special_text) if parts.scheme not in ["https", "http", "ftp", "ftps"] or \ not parts.netloc: log.info("Not accepting URL for image preview: %s" % special_text) return buffer_ = self.textview.tv.get_buffer() if not iter_: iter_ = buffer_.get_end_iter() # Detect XHTML-IM link ttt = buffer_.get_tag_table() tags_ = [(ttt.lookup(t) if isinstance(t, str) else t) for t in other_tags] for t in tags_: is_xhtml_link = getattr(t, 'href', None) if is_xhtml_link: break # Show URL, until image is loaded (if ever) repl_start = buffer_.create_mark(None, iter_, True) buffer_.insert_with_tags(iter_, special_text, \ *[(ttt.lookup(t) if isinstance(t, str) else t) for t in ["url"]]) repl_end = buffer_.create_mark(None, iter_, True) # First get the http head request with does not fetch data, just headers gajim.thread_interface(self._get_http_head, [self.textview.account, special_text], self._check_mime_size, [special_text, repl_start, repl_end]) # Don't print the URL in the message window (in the calling function) self.textview.plugin_modified = True def _check_mime_size(self, (file_mime, file_size), url, repl_start, repl_end): # Check if mime type is acceptable if file_mime == '' and file_size == 0: log.info( "Failed to load HEAD Request for URL: '%s' (see debug log for more info)" % url) # URL is already displayed return if file_mime.lower() not in ACCEPTED_MIME_TYPES: log.info("Not accepted mime type '%s' for URL: '%s'" % (file_mime.lower(), url)) # URL is already displayed return # Check if file size is acceptable if file_size > self.plugin.config['MAX_FILE_SIZE'] or file_size == 0: log.info("File size (%s) too big or unknown (zero) for URL: '%s'" % (str(file_size), url)) # URL is already displayed return # check for encryption (conversations mode) urlparts = urlparse(url) key = '' iv = '' if len(urlparts.fragment): fragment = [] for i in range(0, len(urlparts.fragment), 2): fragment.append(chr(int(urlparts.fragment[i:i + 2], 16))) fragment = ''.join(fragment) key = fragment[16:] iv = fragment[:16] # decrypt if the encryption parameters are correct if len(urlparts.fragment) and len(key) == 32 and len(iv) == 16: def _decryptor( (mem, alt), url, file_mime, repl_start, repl_end, key, iv): if not mem: log.error('Could not download image for URL: %s -- %s' % (url, alt)) return # start self._decrypt_url() in own thread and self._update_img() afterwards gajim.thread_interface( self._decrypt_url, [(mem, alt), key, iv, url], self._update_img, [url, file_mime, repl_start, repl_end, True]) # Start downloading image (_decryptor is callback when download has finished) gajim.thread_interface(self._download_image, [ self.textview.account, { 'src': url, 'max_size': self.plugin.config['MAX_FILE_SIZE'] } ], _decryptor, [url, file_mime, repl_start, repl_end, key, iv])
self._decrypt_url, [(mem, alt), key, iv, url], self._update_img, [url, file_mime, repl_start, repl_end, True]) # Start downloading image (_decryptor is callback when download has finished) gajim.thread_interface(self._download_image, [ self.textview.account, { 'src': url, 'max_size': self.plugin.config['MAX_FILE_SIZE'] } ], _decryptor, [url, file_mime, repl_start, repl_end, key, iv]) else: # Start downloading image (self._update_img() is callback when download has finished) gajim.thread_interface(self._download_image, [ self.textview.account, { 'src': url, 'max_size': self.plugin.config['MAX_FILE_SIZE'] } ], self._update_img, [url, file_mime, repl_start, repl_end]) def _decrypt_url(self, (mem, alt), key, iv, url): try: log.info("Before decrypt image") if decryption_available: log.info("Fast decrypt") mem = self.aes_decrypt_fast(key, iv, mem) else: log.info("Slow decrypt") mem = aes_decrypt(key, iv, mem) log.info("After decrypt image") except Exception: log.error(
def print_special_text(self, tv, special_text, other_tags, graphics=True, iter_=None): conv_textview = tv textview = tv.tv # geo:48.2057365,16.3435941 if not special_text.startswith('geo:'): return buffer_ = textview.get_buffer() if not iter_: iter_ = buffer_.get_end_iter() textview.plugin_modified = True # Show URL, until image is loaded (if ever) ttt = buffer_.get_tag_table() repl_start = buffer_.create_mark(None, iter_, True) buffer_.insert_with_tags( iter_, special_text, *[(ttt.lookup(t) if isinstance(t, str) else t) for t in ["url"]]) repl_end = buffer_.create_mark(None, iter_, True) zoom = 17 size = 250 color = 'blue' coordinates = special_text.split(':')[1] lat = coordinates.split(',')[0] lon = coordinates.split(',')[1] filename = coordinates.replace(',', '_').replace('.', '-') filepath = os.path.join(self.thumbpath, filename) provider = self.config['preview_provider'] # Google if provider == 0: url = 'https://maps.googleapis.com/maps/api/staticmap?center={}' \ '&zoom={}&size={}x{}&markers=color:{}' \ '|label:S|{}'.format(coordinates, zoom, size, size, color, coordinates) weburl = 'https://www.google.at/maps/place/{}'.format(coordinates) else: # Mapquest / OSM apikey = 'F7x36jLVv2hiANVAXmhwvUB044XvGASh' url = 'https://open.mapquestapi.com/staticmap/v4/' \ 'getmap?key={}¢er={}&zoom={}&size={},{}&type=map' \ '&imagetype=png&pois={},{}&scalebar=false' \ .format(apikey, coordinates, zoom, size, size, color, coordinates) weburl = 'http://www.openstreetmap.org/' \ '?mlat={}&mlon={}#map={}/{}/{}&layers=N' \ .format(lat, lon, zoom, lat, lon) log.debug(url) if os.path.exists(filepath): gajim.thread_interface(self.load_thumbnail, [filepath], self.updatechat, [weburl, repl_start, repl_end, textview]) else: gajim.thread_interface(self.download, [url, filepath], self.updatechat, [weburl, repl_start, repl_end, textview]) # Don't print the URL in the message window (in the calling function) conv_textview.plugin_modified = True
def print_special_text(self, special_text, other_tags, graphics=True, iter_=None): # remove qip bbcode special_text = special_text.rsplit('[/img]')[0] if special_text.startswith('www.'): special_text = 'http://' + special_text if special_text.startswith('ftp.'): special_text = 'ftp://' + special_text urlparts = urlparse(special_text) if urlparts.scheme not in ["https", "http", "ftp", "ftps"] or \ not urlparts.netloc: log.info("Not accepting URL for image preview: %s" % special_text) return # Don't print the URL in the message window (in the calling function) self.textview.plugin_modified = True buffer_ = self.textview.tv.get_buffer() if not iter_: iter_ = buffer_.get_end_iter() # Show URL, until image is loaded (if ever) ttt = buffer_.get_tag_table() repl_start = buffer_.create_mark(None, iter_, True) buffer_.insert_with_tags( iter_, special_text, *[(ttt.lookup(t) if isinstance(t, str) else t) for t in ["url"]]) repl_end = buffer_.create_mark(None, iter_, True) filename = os.path.basename(urlparts.path) ext = os.path.splitext(filename)[1] name = os.path.splitext(filename)[0] namehash = hashlib.sha1(special_text).hexdigest() newfilename = name + '_' + namehash + ext thumbfilename = name + '_' + namehash + '_thumb_' \ + str(self.plugin.config['PREVIEW_SIZE']) + ext filepath = os.path.join(self.directory, newfilename) thumbpath = os.path.join(self.thumbpath, thumbfilename) filepaths = [filepath, thumbpath] key = '' iv = '' encrypted = False if len(urlparts.fragment): fragment = [] try: for i in range(0, len(urlparts.fragment), 2): fragment.append(chr(int(urlparts.fragment[i:i + 2], 16))) fragment = ''.join(fragment) key = fragment[16:] iv = fragment[:16] if len(key) == 32 and len(iv) == 16: encrypted = True except: pass # file exists but thumbnail got deleted if os.path.exists(filepath) and not os.path.exists(thumbpath): with open(filepath, 'rb') as f: mem = f.read() f.closed gajim.thread_interface( self._save_thumbnail, [thumbpath, (mem, '')], self._update_img, [special_text, repl_start, repl_end, filepath, encrypted]) # display thumbnail if already downloadeded # (but only if file also exists) elif os.path.exists(filepath) and os.path.exists(thumbpath): gajim.thread_interface( self._load_thumbnail, [thumbpath], self._update_img, [special_text, repl_start, repl_end, filepath, encrypted]) # or download file, calculate thumbnail and finally display it else: if encrypted and not decryption_available: log.debug('Please install Crytography to decrypt pictures') else: # First get the http head request # which does not fetch data, just headers # then check the mime type and filesize gajim.thread_interface(get_http_head, [self.textview.account, special_text], self._check_mime_size, [ special_text, repl_start, repl_end, filepaths, key, iv, encrypted ])
if file_size > self.plugin.config['MAX_FILE_SIZE'] or file_size == 0: log.info("File size (%s) too big or unknown (zero) for URL: '%s'" % (str(file_size), url)) # URL is already displayed return attributes = { 'src': url, 'max_size': self.plugin.config['MAX_FILE_SIZE'], 'filepaths': filepaths, 'key': key, 'iv': iv } gajim.thread_interface( self._download_image, [self.textview.account, attributes, encrypted], self._update_img, [url, repl_start, repl_end, filepaths[0], encrypted]) def _download_image(self, account, attributes, encrypted): filepath = attributes['filepaths'][0] thumbpath = attributes['filepaths'][1] key = attributes['key'] iv = attributes['iv'] mem, alt = get_http_file(account, attributes) # Decrypt file if necessary if encrypted: mem = self._aes_decrypt_fast(key, iv, mem) try: # Write file to harddisk
def _process_img(self, attrs, loaded=None): '''Process a img tag. ''' mem = '' update = False pixbuf = None replace_mark = None replace_tags = None try: if attrs['src'].startswith('data:image/'): # The "data" URL scheme http://tools.ietf.org/html/rfc2397 import base64 img = attrs['src'].split(',')[1] mem = base64.standard_b64decode(urllib2.unquote(img)) elif loaded is not None: (mem, alt, replace_mark, replace_tags) = loaded update = True else: if self.conv_textview: img_mark = self.textbuf.create_mark(None, self.iter, True) gajim.thread_interface(helpers.download_image, [ self.conv_textview.account, attrs], self._update_img, [attrs, img_mark, self._get_style_tags()]) alt = attrs.get('alt', '') if alt: alt += '\n' alt += _('Loading') pixbuf = get_icon_pixmap('gtk-no') if mem: # Caveat: GdkPixbuf is known not to be safe to load # images from network... this program is now potentially # hackable ;) loader = gtk.gdk.PixbufLoader() dims = [0, 0] def height_cb(length): dims[1] = length def width_cb(length): dims[0] = length # process width and height attributes w = attrs.get('width') h = attrs.get('height') # override with width and height styles for attr, val in style_iter(attrs.get('style', '')): if attr == 'width': w = val elif attr == 'height': h = val if w: self._parse_length(w, False, False, 1, 1000, width_cb) if h: self._parse_length(h, False, False, 1, 1000, height_cb) def set_size(pixbuf, w, h, dims): """ FIXME: Floats should be relative to the whole textview, and resize with it. This needs new pifbufs for every resize, gtk.gdk.Pixbuf.scale_simple or similar. """ if isinstance(dims[0], float): dims[0] = int(dims[0]*w) elif not dims[0]: dims[0] = w if isinstance(dims[1], float): dims[1] = int(dims[1]*h) if not dims[1]: dims[1] = h loader.set_size(*dims) if w or h: loader.connect('size-prepared', set_size, dims) loader.write(mem) loader.close() pixbuf = loader.get_pixbuf() alt = attrs.get('alt', '') working_iter = self.iter if replace_mark is not None: working_iter = self.textbuf.get_iter_at_mark(replace_mark) next_iter = working_iter.copy() next_iter.forward_char() self.textbuf.delete(working_iter, next_iter) self.textbuf.delete_mark(replace_mark) if pixbuf is not None: if replace_mark: tags = replace_tags else: tags = self._get_style_tags() if tags: tmpmark = self.textbuf.create_mark(None, working_iter, True) self.textbuf.insert_pixbuf(working_iter, pixbuf) self.starting = False if tags: start = self.textbuf.get_iter_at_mark(tmpmark) for tag in tags: self.textbuf.apply_tag(tag, start, working_iter) self.textbuf.delete_mark(tmpmark) else: self._insert_text('[IMG: %s]' % alt, working_iter) except Exception, ex: log.error('Error loading image ' + str(ex)) pixbuf = None alt = attrs.get('alt', 'Broken image') try: loader.close() except Exception: pass
def print_special_text(self, special_text, other_tags, graphics=True, iter__=None): if gajim.interface.sharp_slash_re.match(special_text): # insert post num #123456// buffer_, iter_, tag = self.get_iter_and_tag('sharp_slash') buffer_.insert_with_tags(iter__, special_text, tag) self.last_juick_num = special_text self.textview.plugin_modified = True return if gajim.interface.juick_nick_re.match(special_text): # insert juick nick @nickname//// buffer_, iter_, tag = self.get_iter_and_tag('juick_nick') mark = buffer_.create_mark(None, iter__, True) nick = special_text[1:].rstrip(':') buffer_.insert_with_tags(iter__, special_text, tag) # insert avatars if not self.plugin.config['SHOW_AVATARS']: self.textview.plugin_modified = True return b_nick = buffer_.get_text(buffer_.get_start_iter(), buffer_.get_iter_at_mark(mark),False) if self.plugin.config['ONLY_AUTHOR_AVATAR'] and not \ special_text.endswith(':') and b_nick[-9:] not in ('Subscribed to ' ): self.textview.plugin_modified = True return if self.plugin.config['ONLY_FIRST_AVATAR']: if b_nick[-9:] not in ('Reply by ', 'message from ', 'ended by ', 'Subscribed to '): if b_nick[-2] != gajim.config.get('after_nickname'): self.textview.plugin_modified = True return elif b_nick[-1] == '\n': self.textview.plugin_modified = True return conn = gajim.connections[self.chat_control.account] if not conn.connected: self.textview.plugin_modified = True return # search id in the db query = "select nick, id from person where nick = :nick" self.plugin.cursor.execute(query, {'nick':nick}) db_item = self.plugin.cursor.fetchone() if db_item: # nick in the db pixbuf = self.get_avatar(db_item[1], nick, True) if not pixbuf: self.textview.plugin_modified = True return gobject.idle_add(self.set_avatar, mark, nick, pixbuf) self.textview.plugin_modified = True return else: # nick not in the db gobject.idle_add(self.get_new_avatar, mark, nick) self.textview.plugin_modified = True return if gajim.interface.juick_pic_re.match(special_text) and \ self.plugin.config['SHOW_PREVIEW']: # show pics preview buffer_, iter_, tag = self.get_iter_and_tag('url') mark = buffer_.create_mark(None, buffer_.get_end_iter(), True) uid = special_text.split('/')[-1] url = "http://i.juick.com/photos-512/%s" % uid gajim.thread_interface(self.insert_pic_preview, [mark, special_text, url, tag]) self.textview.plugin_modified = True return
def print_special_text(self, special_text, other_tags, graphics=True, iter__=None): if gajim.interface.sharp_slash_re.match(special_text): # insert post num #123456// buffer_, iter_, tag = self.get_iter_and_tag("sharp_slash") buffer_.insert_with_tags(iter__, special_text, tag) self.last_juick_num = special_text self.textview.plugin_modified = True return if gajim.interface.juick_nick_re.match(special_text): # insert juick nick @nickname//// buffer_, iter_, tag = self.get_iter_and_tag("juick_nick") mark = buffer_.create_mark(None, iter__, True) nick = special_text[1:].rstrip(":") buffer_.insert_with_tags(iter__, special_text, tag) # insert avatars if not self.plugin.config["SHOW_AVATARS"]: self.textview.plugin_modified = True return b_nick = buffer_.get_text(buffer_.get_start_iter(), buffer_.get_iter_at_mark(mark), False) if ( self.plugin.config["ONLY_AUTHOR_AVATAR"] and not special_text.endswith(":") and b_nick[-9:] not in ("Subscribed to ") ): self.textview.plugin_modified = True return if self.plugin.config["ONLY_FIRST_AVATAR"]: if b_nick[-9:] not in ("Reply by ", "message from ", "ended by ", "Subscribed to "): if b_nick[-2] != gajim.config.get("after_nickname"): self.textview.plugin_modified = True return elif b_nick[-1] == "\n": self.textview.plugin_modified = True return conn = gajim.connections[self.chat_control.account] if not conn.connected: self.textview.plugin_modified = True return # search id in the db query = "select nick, id from person where nick = :nick" self.plugin.cursor.execute(query, {"nick": nick}) db_item = self.plugin.cursor.fetchone() if db_item: # nick in the db pixbuf = self.get_avatar(db_item[1], nick, True) if not pixbuf: self.textview.plugin_modified = True return gobject.idle_add(self.set_avatar, mark, nick, pixbuf) self.textview.plugin_modified = True return else: # nick not in the db gobject.idle_add(self.get_new_avatar, mark, nick) self.textview.plugin_modified = True return if gajim.interface.juick_pic_re.match(special_text) and self.plugin.config["SHOW_PREVIEW"]: # show pics preview buffer_, iter_, tag = self.get_iter_and_tag("url") mark = buffer_.create_mark(None, buffer_.get_end_iter(), True) uid = special_text.split("/")[-1] url = "http://i.juick.com/photos-512/%s" % uid gajim.thread_interface(self.insert_pic_preview, [mark, special_text, url, tag]) self.textview.plugin_modified = True return
def print_special_text(self, special_text, other_tags, graphics=True, iter_=None): # remove qip bbcode special_text = special_text.rsplit('[/img]')[0] if special_text.startswith('www.'): special_text = 'http://' + special_text if special_text.startswith('ftp.'): special_text = 'ftp://' + special_text urlparts = urlparse(special_text) if urlparts.scheme not in ["https", "http", "ftp", "ftps"] or \ not urlparts.netloc: log.info("Not accepting URL for image preview: %s" % special_text) return # Don't print the URL in the message window (in the calling function) self.textview.plugin_modified = True buffer_ = self.textview.tv.get_buffer() if not iter_: iter_ = buffer_.get_end_iter() # Show URL, until image is loaded (if ever) ttt = buffer_.get_tag_table() repl_start = buffer_.create_mark(None, iter_, True) buffer_.insert_with_tags(iter_, special_text, *[(ttt.lookup(t) if isinstance(t, str) else t) for t in ["url"]]) repl_end = buffer_.create_mark(None, iter_, True) filename = os.path.basename(urlparts.path) ext = os.path.splitext(filename)[1] name = os.path.splitext(filename)[0] namehash = hashlib.sha1(special_text).hexdigest() newfilename = name + '_' + namehash + ext thumbfilename = name + '_' + namehash + '_thumb_' \ + str(self.plugin.config['PREVIEW_SIZE']) + ext filepath = os.path.join(self.directory, newfilename) thumbpath = os.path.join(self.thumbpath, thumbfilename) filepaths = [filepath, thumbpath] key = '' iv = '' encrypted = False if len(urlparts.fragment): fragment = [] for i in range(0, len(urlparts.fragment), 2): fragment.append(chr(int(urlparts.fragment[i:i + 2], 16))) fragment = ''.join(fragment) key = fragment[16:] iv = fragment[:16] if len(key) == 32 and len(iv) == 16: encrypted = True # file exists but thumbnail got deleted if os.path.exists(filepath) and not os.path.exists(thumbpath): with open(filepath, 'rb') as f: mem = f.read() f.closed gajim.thread_interface( self._save_thumbnail, [thumbpath, (mem, '')], self._update_img, [special_text, repl_start, repl_end, filepath, encrypted]) # display thumbnail if already downloadeded # (but only if file also exists) elif os.path.exists(filepath) and os.path.exists(thumbpath): gajim.thread_interface( self._load_thumbnail, [thumbpath], self._update_img, [special_text, repl_start, repl_end, filepath, encrypted]) # or download file, calculate thumbnail and finally display it else: if encrypted and not decryption_available: log.debug('Please install Crytography to decrypt pictures') else: # First get the http head request # which does not fetch data, just headers # then check the mime type and filesize gajim.thread_interface( get_http_head, [self.textview.account, special_text], self._check_mime_size, [special_text, repl_start, repl_end, filepaths, key, iv, encrypted])
# Check if file size is acceptable if file_size > self.plugin.config['MAX_FILE_SIZE'] or file_size == 0: log.info("File size (%s) too big or unknown (zero) for URL: '%s'" % (str(file_size), url)) # URL is already displayed return attributes = {'src': url, 'max_size': self.plugin.config['MAX_FILE_SIZE'], 'filepaths': filepaths, 'key': key, 'iv': iv} gajim.thread_interface( self._download_image, [self.textview.account, attributes, encrypted], self._update_img, [url, repl_start, repl_end, filepaths[0], encrypted]) def _download_image(self, account, attributes, encrypted): filepath = attributes['filepaths'][0] thumbpath = attributes['filepaths'][1] key = attributes['key'] iv = attributes['iv'] mem, alt = get_http_file(account, attributes) # Decrypt file if necessary if encrypted: mem = self._aes_decrypt_fast(key, iv, mem) try: