| 192 | | if config.get('emoticons_theme'): |
| 193 | | # When an emoticon is bordered by an alpha-numeric character it is NOT |
| 194 | | # expanded. e.g., foo:) NO, foo :) YES, (brb) NO, (:)) YES, etc. |
| 195 | | # We still allow multiple emoticons side-by-side like :P:P:P |
| 196 | | # sort keys by length so :qwe emot is checked before :q |
| 197 | | keys = interface.emoticons.keys() |
| 198 | | keys.sort(interface.on_emoticon_sort) |
| 199 | | emoticons_pattern_prematch = '' |
| 200 | | emoticons_pattern_postmatch = '' |
| 201 | | emoticon_length = 0 |
| 202 | | for emoticon in keys: # travel thru emoticons list |
| 203 | | emoticon_escaped = re.escape(emoticon) # espace regexp metachars |
| 204 | | emoticons_pattern += emoticon_escaped + '|'# | means or in regexp |
| 205 | | if (emoticon_length != len(emoticon)): |
| 206 | | # Build up expressions to match emoticons next to other emoticons |
| 207 | | emoticons_pattern_prematch = emoticons_pattern_prematch[:-1] + ')|(?<=' |
| 208 | | emoticons_pattern_postmatch = emoticons_pattern_postmatch[:-1] + ')|(?=' |
| 209 | | emoticon_length = len(emoticon) |
| 210 | | emoticons_pattern_prematch += emoticon_escaped + '|' |
| 211 | | emoticons_pattern_postmatch += emoticon_escaped + '|' |
| 212 | | # We match from our list of emoticons, but they must either have |
| 213 | | # whitespace, or another emoticon next to it to match successfully |
| 214 | | # [\w.] alphanumeric and dot (for not matching 8) in (2.8)) |
| 215 | | emoticons_pattern = '|' + \ |
| | 189 | try: |
| | 190 | if config.get('emoticons_theme'): |
| | 191 | # When an emoticon is bordered by an alpha-numeric character it is NOT |
| | 192 | # expanded. e.g., foo:) NO, foo :) YES, (brb) NO, (:)) YES, etc. |
| | 193 | # We still allow multiple emoticons side-by-side like :P:P:P |
| | 194 | # sort keys by length so :qwe emot is checked before :q |
| | 195 | keys = interface.emoticons.keys() |
| | 196 | keys.sort(interface.on_emoticon_sort) |
| | 197 | emoticons_pattern_prematch = '' |
| | 198 | emoticons_pattern_postmatch = '' |
| | 199 | emoticon_length = 0 |
| | 200 | for emoticon in keys: # travel thru emoticons list |
| | 201 | emoticon_escaped = re.escape(emoticon) # espace regexp metachars |
| | 202 | emoticons_pattern += emoticon_escaped + '|'# | means or in regexp |
| | 203 | if (emoticon_length != len(emoticon)): |
| | 204 | # Build up expressions to match emoticons next to other emoticons |
| | 205 | emoticons_pattern_prematch = emoticons_pattern_prematch[:-1] + ')|(?<=' |
| | 206 | emoticons_pattern_postmatch = emoticons_pattern_postmatch[:-1] + ')|(?=' |
| | 207 | emoticon_length = len(emoticon) |
| | 208 | emoticons_pattern_prematch += emoticon_escaped + '|' |
| | 209 | emoticons_pattern_postmatch += emoticon_escaped + '|' |
| | 210 | # We match from our list of emoticons, but they must either have |
| | 211 | # whitespace, or another emoticon next to it to match successfully |
| | 212 | # [\w.] alphanumeric and dot (for not matching 8) in (2.8)) |
| | 213 | emoticons_pattern = '|' + \ |
| | 501 | |
| | 502 | def __length_tag_cb(self, value, tag, propname): |
| | 503 | try: |
| | 504 | tag.set_property(propname, value) |
| | 505 | except: |
| | 506 | gajim.log.warn( "Error with prop: " + propname + " for tag: " + str(tag)) |
| | 507 | |
| | 508 | |
| | 509 | def _parse_style_width(self, tag, value): |
| | 510 | if value == 'auto': |
| | 511 | return |
| | 512 | self._parse_length(value, False, False, 1, 1000, self.__length_tag_cb, |
| | 513 | tag, "width") |
| | 514 | def _parse_style_height(self, tag, value): |
| | 515 | if value == 'auto': |
| | 516 | return |
| | 517 | self._parse_length(value, False, False, 1, 1000, self.__length_tag_cb, |
| | 518 | tag, "height") |
| 476 | | for style in ["background-color", "color", "font-family", "font-size", |
| 477 | | "font-style", "font-weight", "margin-left", "margin-right", |
| 478 | | "text-align", "text-decoration", "white-space", 'display' ]: |
| | 523 | for style in ['background-color', 'color', 'font-family', 'font-size', |
| | 524 | 'font-style', 'font-weight', 'margin-left', 'margin-right', |
| | 525 | 'text-align', 'text-decoration', 'white-space', 'display', |
| | 526 | 'width', 'height' ]: |
| | 554 | def _process_img(self, attrs): |
| | 555 | '''Process a img tag. |
| | 556 | ''' |
| | 557 | try: |
| | 558 | # Wait maximum 1s for connection |
| | 559 | socket.setdefaulttimeout(1) |
| | 560 | try: |
| | 561 | f = urllib2.urlopen(attrs['src']) |
| | 562 | except Exception, ex: |
| | 563 | gajim.log.debug(str('Error loading image %s ' % attrs['src'] + ex)) |
| | 564 | pixbuf = None |
| | 565 | alt = attrs.get('alt', 'Broken image') |
| | 566 | else: |
| | 567 | # Wait 0.1s between each byte |
| | 568 | try: |
| | 569 | f.fp._sock.fp._sock.settimeout(0.5) |
| | 570 | except: |
| | 571 | pass |
| | 572 | # Max image size = 2 MB (to try to prevent DoS) |
| | 573 | mem = '' |
| | 574 | deadline = time.time() + 3 |
| | 575 | while True: |
| | 576 | if time.time() > deadline: |
| | 577 | gajim.log.debug(str('Timeout loading image %s ' % \ |
| | 578 | attrs['src'] + ex)) |
| | 579 | mem = '' |
| | 580 | alt = attrs.get('alt', '') |
| | 581 | if alt: |
| | 582 | alt += '\n' |
| | 583 | alt += _('Timeout loading image') |
| | 584 | break |
| | 585 | try: |
| | 586 | temp = f.read(100) |
| | 587 | except socket.timeout, ex: |
| | 588 | gajim.log.debug('Timeout loading image %s ' % attrs['src'] + \ |
| | 589 | str(ex)) |
| | 590 | mem = '' |
| | 591 | alt = attrs.get('alt', '') |
| | 592 | if alt: |
| | 593 | alt += '\n' |
| | 594 | alt += _('Timeout loading image') |
| | 595 | break |
| | 596 | if temp: |
| | 597 | mem += temp |
| | 598 | else: |
| | 599 | break |
| | 600 | if len(mem) > 2*1024*1024: |
| | 601 | alt = attrs.get('alt', '') |
| | 602 | if alt: |
| | 603 | alt += '\n' |
| | 604 | alt += _('Image is too big') |
| | 605 | break |
| | 606 | pixbuf = None |
| | 607 | if mem: |
| | 608 | # Caveat: GdkPixbuf is known not to be safe to load |
| | 609 | # images from network... this program is now potentially |
| | 610 | # hackable ;) |
| | 611 | loader = gtk.gdk.PixbufLoader() |
| | 612 | dims = [0,0] |
| | 613 | def height_cb(length): |
| | 614 | dims[1] = length |
| | 615 | def width_cb(length): |
| | 616 | dims[0] = length |
| | 617 | # process width and height attributes |
| | 618 | w = attrs.get('width') |
| | 619 | h = attrs.get('height') |
| | 620 | # override with width and height styles |
| | 621 | for attr, val in style_iter(attrs.get('style', '')): |
| | 622 | if attr == 'width': |
| | 623 | w = val |
| | 624 | elif attr == 'height': |
| | 625 | h = val |
| | 626 | if w: |
| | 627 | self._parse_length(w, False, False, 1, 1000, width_cb) |
| | 628 | if h: |
| | 629 | self._parse_length(h, False, False, 1, 1000, height_cb) |
| | 630 | def set_size(pixbuf, w, h, dims): |
| | 631 | '''FIXME: floats should be relative to the whole |
| | 632 | textview, and resize with it. This needs new |
| | 633 | pifbufs for every resize, gtk.gdk.Pixbuf.scale_simple |
| | 634 | or similar. |
| | 635 | ''' |
| | 636 | if type(dims[0]) == float: |
| | 637 | dims[0] = int(dims[0]*w) |
| | 638 | elif not dims[0]: |
| | 639 | dims[0] = w |
| | 640 | if type(dims[1]) == float: |
| | 641 | dims[1] = int(dims[1]*h) |
| | 642 | if not dims[1]: |
| | 643 | dims[1] = h |
| | 644 | loader.set_size(*dims) |
| | 645 | if w or h: |
| | 646 | loader.connect('size-prepared', set_size, dims) |
| | 647 | loader.write(mem) |
| | 648 | loader.close() |
| | 649 | pixbuf = loader.get_pixbuf() |
| | 650 | alt = attrs.get('alt', '') |
| | 651 | if pixbuf is not None: |
| | 652 | tags = self._get_style_tags() |
| | 653 | if tags: |
| | 654 | tmpmark = self.textbuf.create_mark(None, self.iter, True) |
| | 655 | self.textbuf.insert_pixbuf(self.iter, pixbuf) |
| | 656 | self.starting = False |
| | 657 | if tags: |
| | 658 | start = self.textbuf.get_iter_at_mark(tmpmark) |
| | 659 | for tag in tags: |
| | 660 | self.textbuf.apply_tag(tag, start, self.iter) |
| | 661 | self.textbuf.delete_mark(tmpmark) |
| | 662 | else: |
| | 663 | self._insert_text('[IMG: %s]' % alt) |
| | 664 | except Exception, ex: |
| | 665 | gajim.log.error('Error loading image ' + str(ex)) |
| | 666 | pixbuf = None |
| | 667 | alt = attrs.get('alt', 'Broken image') |
| | 668 | try: |
| | 669 | loader.close() |
| | 670 | except: |
| | 671 | pass |
| | 672 | return pixbuf |
| 684 | | elif name == 'img': |
| 685 | | # Wait maximum 1s for connection |
| 686 | | socket.setdefaulttimeout(1) |
| 687 | | try: |
| 688 | | f = urllib2.urlopen(attrs['src']) |
| 689 | | except Exception, ex: |
| 690 | | gajim.log.debug(str('Error loading image %s ' % attrs['src'] + ex)) |
| 691 | | pixbuf = None |
| 692 | | alt = attrs.get('alt', 'Broken image') |
| 693 | | else: |
| 694 | | # Wait 10ms between each byte |
| 695 | | try: |
| 696 | | f.fp._sock.fp._sock.settimeout(0.1) |
| 697 | | except: |
| 698 | | pass |
| 699 | | # Max image size = 2 MB (to try to prevent DoS) in Max 3s |
| 700 | | mem = '' |
| 701 | | deadline = time.time() + 3 |
| 702 | | while True: |
| 703 | | if time.time() > deadline: |
| 704 | | gajim.log.debug(str('Timeout loading image %s ' % \ |
| 705 | | attrs['src'] + ex)) |
| 706 | | mem = '' |
| 707 | | alt = attrs.get('alt', '') |
| 708 | | if alt: |
| 709 | | alt += '\n' |
| 710 | | alt += _('Timeout loading image') |
| 711 | | break |
| 712 | | try: |
| 713 | | temp = f.read(100) |
| 714 | | except socket.timeout, ex: |
| 715 | | gajim.log.debug('Timeout loading image %s ' % attrs['src'] + \ |
| 716 | | str(ex)) |
| 717 | | mem = '' |
| 718 | | alt = attrs.get('alt', '') |
| 719 | | if alt: |
| 720 | | alt += '\n' |
| 721 | | alt += _('Timeout loading image') |
| 722 | | break |
| 723 | | if temp: |
| 724 | | mem += temp |
| 725 | | else: |
| 726 | | break |
| 727 | | if len(mem) > 2*1024*1024: |
| 728 | | alt = attrs.get('alt', '') |
| 729 | | if alt: |
| 730 | | alt += '\n' |
| 731 | | alt += _('Image is too big') |
| 732 | | break |
| 733 | | |
| 734 | | if mem: |
| 735 | | # Caveat: GdkPixbuf is known not to be safe to load |
| 736 | | # images from network... this program is now potentially |
| 737 | | # hackable ;) |
| 738 | | loader = gtk.gdk.PixbufLoader() |
| 739 | | loader.write(mem) |
| 740 | | loader.close() |
| 741 | | pixbuf = loader.get_pixbuf() |
| 742 | | else: |
| 743 | | pixbuf = None |
| 744 | | if pixbuf is not None: |
| 745 | | tags = self._get_style_tags() |
| 746 | | if tags: |
| 747 | | tmpmark = self.textbuf.create_mark(None, self.iter, True) |
| 748 | | |
| 749 | | self.textbuf.insert_pixbuf(self.iter, pixbuf) |
| 750 | | |
| 751 | | if tags: |
| 752 | | start = self.textbuf.get_iter_at_mark(tmpmark) |
| 753 | | for tag in tags: |
| 754 | | self.textbuf.apply_tag(tag, start, self.iter) |
| 755 | | self.textbuf.delete_mark(tmpmark) |
| 756 | | else: |
| 757 | | |