| 1 | # -*- coding:utf-8 -*- |
|---|
| 2 | ## src/features_window.py |
|---|
| 3 | ## |
|---|
| 4 | ## Copyright (C) 2007 Jean-Marie Traissard <jim AT lapin.org> |
|---|
| 5 | ## Julien Pivotto <roidelapluie AT gmail.com> |
|---|
| 6 | ## Stefan Bethge <stefan AT lanpartei.de> |
|---|
| 7 | ## Stephan Erb <steve-e AT h3c.de> |
|---|
| 8 | ## Copyright (C) 2007-2008 Yann Leboulanger <asterix AT lagaule.org> |
|---|
| 9 | ## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org> |
|---|
| 10 | ## |
|---|
| 11 | ## This file is part of Gajim. |
|---|
| 12 | ## |
|---|
| 13 | ## Gajim is free software; you can redistribute it and/or modify |
|---|
| 14 | ## it under the terms of the GNU General Public License as published |
|---|
| 15 | ## by the Free Software Foundation; version 3 only. |
|---|
| 16 | ## |
|---|
| 17 | ## Gajim is distributed in the hope that it will be useful, |
|---|
| 18 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 19 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 20 | ## GNU General Public License for more details. |
|---|
| 21 | ## |
|---|
| 22 | ## You should have received a copy of the GNU General Public License |
|---|
| 23 | ## along with Gajim. If not, see <http://www.gnu.org/licenses/>. |
|---|
| 24 | ## |
|---|
| 25 | |
|---|
| 26 | import os |
|---|
| 27 | import sys |
|---|
| 28 | import gtk |
|---|
| 29 | import gtkgui_helpers |
|---|
| 30 | |
|---|
| 31 | import dialogs |
|---|
| 32 | |
|---|
| 33 | from common import gajim |
|---|
| 34 | from common import helpers |
|---|
| 35 | |
|---|
| 36 | import random |
|---|
| 37 | from tempfile import gettempdir |
|---|
| 38 | from subprocess import Popen |
|---|
| 39 | |
|---|
| 40 | class FeaturesWindow: |
|---|
| 41 | '''Class for features window''' |
|---|
| 42 | |
|---|
| 43 | def __init__(self): |
|---|
| 44 | self.xml = gtkgui_helpers.get_glade('features_window.glade') |
|---|
| 45 | self.window = self.xml.get_widget('features_window') |
|---|
| 46 | treeview = self.xml.get_widget('features_treeview') |
|---|
| 47 | self.desc_label = self.xml.get_widget('feature_desc_label') |
|---|
| 48 | |
|---|
| 49 | # {name: (available_function, unix_text, windows_text)} |
|---|
| 50 | self.features = { |
|---|
| 51 | _('PyOpenSSL'): (self.pyopenssl_available, |
|---|
| 52 | _('A library used to validate server certificates to ensure a secure connection.'), |
|---|
| 53 | _('Requires python-pyopenssl.'), |
|---|
| 54 | _('Requires python-pyopenssl.')), |
|---|
| 55 | _('Bonjour / Zeroconf'): (self.zeroconf_available, |
|---|
| 56 | _('Serverless chatting with autodetected clients in a local network.'), |
|---|
| 57 | _('Requires python-avahi.'), |
|---|
| 58 | _('Requires pybonjour (http://o2s.csail.mit.edu/o2s-wiki/pybonjour).')), |
|---|
| 59 | _('gajim-remote'): (self.dbus_available, |
|---|
| 60 | _('A script to control Gajim via commandline.'), |
|---|
| 61 | _('Requires python-dbus.'), |
|---|
| 62 | _('Feature not available under Windows.')), |
|---|
| 63 | _('OpenGPG'): (self.gpg_available, |
|---|
| 64 | _('Encrypting chatmessages with gpg keys.'), |
|---|
| 65 | _('Requires gpg and python-GnuPGInterface.'), |
|---|
| 66 | _('Feature not available under Windows.')), |
|---|
| 67 | _('network-manager'): (self.network_manager_available, |
|---|
| 68 | _('Autodetection of network status.'), |
|---|
| 69 | _('Requires gnome-network-manager and python-dbus.'), |
|---|
| 70 | _('Feature not available under Windows.')), |
|---|
| 71 | _('Session Management'): (self.session_management_available, |
|---|
| 72 | _('Gajim session is stored on logout and restored on login.'), |
|---|
| 73 | _('Requires python-gnome2.'), |
|---|
| 74 | _('Feature not available under Windows.')), |
|---|
| 75 | _('gnome-keyring'): (self.gnome_keyring_available, |
|---|
| 76 | _('Passwords can be stored securely and not just in plaintext.'), |
|---|
| 77 | _('Requires gnome-keyring and python-gnome2-desktop.'), |
|---|
| 78 | _('Feature not available under Windows.')), |
|---|
| 79 | _('SRV'): (self.srv_available, |
|---|
| 80 | _('Ability to connect to servers which are using SRV records.'), |
|---|
| 81 | _('Requires dnsutils.'), |
|---|
| 82 | _('Requires nslookup to use SRV records.')), |
|---|
| 83 | _('Spell Checker'): (self.speller_available, |
|---|
| 84 | _('Spellchecking of composed messages.'), |
|---|
| 85 | _('Requires python-gnome2-extras or compilation of gtkspell module from Gajim sources.'), |
|---|
| 86 | _('Feature not available under Windows.')), |
|---|
| 87 | _('Notification-daemon'): (self.notification_available, |
|---|
| 88 | _('Passive popups notifying for new events.'), |
|---|
| 89 | _('Requires python-notify or instead python-dbus in conjunction with notification-daemon.'), |
|---|
| 90 | _('Feature not available under Windows.')), |
|---|
| 91 | _('Trayicon'): (self.trayicon_available, |
|---|
| 92 | _('A icon in systemtray reflecting the current presence.'), |
|---|
| 93 | _('Requires python-gnome2-extras or compiled trayicon module from Gajim sources.'), |
|---|
| 94 | _('Requires PyGTK >= 2.10.')), |
|---|
| 95 | _('Idle'): (self.idle_available, |
|---|
| 96 | _('Ability to measure idle time, in order to set auto status.'), |
|---|
| 97 | _('Requires compilation of the idle module from Gajim sources.'), |
|---|
| 98 | _('Requires compilation of the idle module from Gajim sources.')), |
|---|
| 99 | _('LaTeX'): (self.latex_available, |
|---|
| 100 | _('Transform LaTeX expressions between $$ $$.'), |
|---|
| 101 | _('Requires texlive-latex-base and dvipng. You have to set \'use_latex\' to True in the Advanced Configuration Editor.'), |
|---|
| 102 | _('Requires texlive-latex-base and dvipng (All is in MikTeX). You have to set \'use_latex\' to True in the Advanced Configuration Editor.')), |
|---|
| 103 | _('End to End Encryption'): (self.pycrypto_available, |
|---|
| 104 | _('Encrypting chatmessages.'), |
|---|
| 105 | _('Requires python-crypto.'), |
|---|
| 106 | _('Requires python-crypto.')), |
|---|
| 107 | _('RST Generator'): (self.docutils_available, |
|---|
| 108 | _('Generate XHTML output from RST code (see http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html).'), |
|---|
| 109 | _('Requires python-docutils.'), |
|---|
| 110 | _('Requires python-docutils.')), |
|---|
| 111 | _('libsexy'): (self.pysexy_available, |
|---|
| 112 | _('Ability to have clickable URLs in chat and groupchat window banners.'), |
|---|
| 113 | _('Requires python-sexy.'), |
|---|
| 114 | _('Requires python-sexy.')), |
|---|
| 115 | } |
|---|
| 116 | |
|---|
| 117 | # name, supported |
|---|
| 118 | self.model = gtk.ListStore(str, bool) |
|---|
| 119 | treeview.set_model(self.model) |
|---|
| 120 | |
|---|
| 121 | col = gtk.TreeViewColumn(_('Available')) |
|---|
| 122 | treeview.append_column(col) |
|---|
| 123 | cell = gtk.CellRendererToggle() |
|---|
| 124 | cell.set_property('radio', True) |
|---|
| 125 | col.pack_start(cell) |
|---|
| 126 | col.set_attributes(cell, active = 1) |
|---|
| 127 | |
|---|
| 128 | col = gtk.TreeViewColumn(_('Feature')) |
|---|
| 129 | treeview.append_column(col) |
|---|
| 130 | cell = gtk.CellRendererText() |
|---|
| 131 | col.pack_start(cell, expand = True) |
|---|
| 132 | col.add_attribute(cell, 'text', 0) |
|---|
| 133 | |
|---|
| 134 | # Fill model |
|---|
| 135 | for feature in self.features: |
|---|
| 136 | func = self.features[feature][0] |
|---|
| 137 | rep = func() |
|---|
| 138 | self.model.append([feature, rep]) |
|---|
| 139 | self.xml.signal_autoconnect(self) |
|---|
| 140 | self.window.show_all() |
|---|
| 141 | self.xml.get_widget('close_button').grab_focus() |
|---|
| 142 | |
|---|
| 143 | def on_close_button_clicked(self, widget): |
|---|
| 144 | self.window.destroy() |
|---|
| 145 | |
|---|
| 146 | def on_features_treeview_cursor_changed(self, widget): |
|---|
| 147 | selection = widget.get_selection() |
|---|
| 148 | if not selection: |
|---|
| 149 | return |
|---|
| 150 | rows = selection.get_selected_rows()[1] |
|---|
| 151 | if not rows: |
|---|
| 152 | return |
|---|
| 153 | path = rows[0] |
|---|
| 154 | available = self.model[path][1] |
|---|
| 155 | feature = self.model[path][0].decode('utf-8') |
|---|
| 156 | text = self.features[feature][1] + '\n' |
|---|
| 157 | if os.name == 'nt': |
|---|
| 158 | text = text + self.features[feature][3] |
|---|
| 159 | else: |
|---|
| 160 | text = text + self.features[feature][2] |
|---|
| 161 | self.desc_label.set_text(text) |
|---|
| 162 | |
|---|
| 163 | def pyopenssl_available(self): |
|---|
| 164 | try: |
|---|
| 165 | import OpenSSL.SSL |
|---|
| 166 | import OpenSSL.crypto |
|---|
| 167 | except Exception: |
|---|
| 168 | return False |
|---|
| 169 | return True |
|---|
| 170 | |
|---|
| 171 | def zeroconf_available(self): |
|---|
| 172 | try: |
|---|
| 173 | import avahi |
|---|
| 174 | except Exception: |
|---|
| 175 | try: |
|---|
| 176 | import pybonjour |
|---|
| 177 | except Exception: |
|---|
| 178 | return False |
|---|
| 179 | return True |
|---|
| 180 | |
|---|
| 181 | def dbus_available(self): |
|---|
| 182 | if os.name == 'nt': |
|---|
| 183 | return False |
|---|
| 184 | from common import dbus_support |
|---|
| 185 | return dbus_support.supported |
|---|
| 186 | |
|---|
| 187 | def gpg_available(self): |
|---|
| 188 | if os.name == 'nt': |
|---|
| 189 | return False |
|---|
| 190 | from common import gajim |
|---|
| 191 | return gajim.HAVE_GPG |
|---|
| 192 | |
|---|
| 193 | def network_manager_available(self): |
|---|
| 194 | if os.name == 'nt': |
|---|
| 195 | return False |
|---|
| 196 | import network_manager_listener |
|---|
| 197 | return network_manager_listener.supported |
|---|
| 198 | |
|---|
| 199 | def session_management_available(self): |
|---|
| 200 | if os.name == 'nt': |
|---|
| 201 | return False |
|---|
| 202 | try: |
|---|
| 203 | import gnome.ui |
|---|
| 204 | except Exception: |
|---|
| 205 | return False |
|---|
| 206 | return True |
|---|
| 207 | |
|---|
| 208 | def gnome_keyring_available(self): |
|---|
| 209 | if os.name == 'nt': |
|---|
| 210 | return False |
|---|
| 211 | try: |
|---|
| 212 | import gnomekeyring |
|---|
| 213 | except Exception: |
|---|
| 214 | return False |
|---|
| 215 | return True |
|---|
| 216 | |
|---|
| 217 | def srv_available(self): |
|---|
| 218 | return helpers.is_in_path('nslookup') |
|---|
| 219 | |
|---|
| 220 | def speller_available(self): |
|---|
| 221 | if os.name == 'nt': |
|---|
| 222 | return False |
|---|
| 223 | try: |
|---|
| 224 | import gtkspell |
|---|
| 225 | except Exception: |
|---|
| 226 | return False |
|---|
| 227 | return True |
|---|
| 228 | |
|---|
| 229 | def notification_available(self): |
|---|
| 230 | if os.name == 'nt': |
|---|
| 231 | return False |
|---|
| 232 | elif sys.platform == 'darwin': |
|---|
| 233 | try: |
|---|
| 234 | import osx.growler |
|---|
| 235 | except Exception: |
|---|
| 236 | return False |
|---|
| 237 | return True |
|---|
| 238 | from common import dbus_support |
|---|
| 239 | if self.dbus_available() and dbus_support.get_notifications_interface(): |
|---|
| 240 | return True |
|---|
| 241 | try: |
|---|
| 242 | import pynotify |
|---|
| 243 | except Exception: |
|---|
| 244 | return False |
|---|
| 245 | return True |
|---|
| 246 | |
|---|
| 247 | def trayicon_available(self): |
|---|
| 248 | if os.name == 'nt' and gtk.pygtk_version >= (2, 10, 0) and \ |
|---|
| 249 | gtk.gtk_version >= (2, 10, 0): |
|---|
| 250 | return True |
|---|
| 251 | try: |
|---|
| 252 | import systray |
|---|
| 253 | except Exception: |
|---|
| 254 | return False |
|---|
| 255 | return True |
|---|
| 256 | |
|---|
| 257 | def idle_available(self): |
|---|
| 258 | from common import sleepy |
|---|
| 259 | return sleepy.SUPPORTED |
|---|
| 260 | |
|---|
| 261 | def latex_available(self): |
|---|
| 262 | '''check is latex is available and if it can create a picture.''' |
|---|
| 263 | |
|---|
| 264 | exitcode = 0 |
|---|
| 265 | random.seed() |
|---|
| 266 | tmpfile = os.path.join(gettempdir(), "gajimtex_" + \ |
|---|
| 267 | random.randint(0,100).__str__()) |
|---|
| 268 | |
|---|
| 269 | # build latex string |
|---|
| 270 | texstr = '\\documentclass[12pt]{article}\\usepackage[dvips]{graphicx}' |
|---|
| 271 | texstr += '\\usepackage{amsmath}\\usepackage{amssymb}\\pagestyle{empty}' |
|---|
| 272 | texstr += '\\begin{document}\\begin{large}\\begin{gather*}test' |
|---|
| 273 | texstr += '\\end{gather*}\\end{large}\\end{document}' |
|---|
| 274 | |
|---|
| 275 | file = open(os.path.join(tmpfile + ".tex"), "w+") |
|---|
| 276 | file.write(texstr) |
|---|
| 277 | file.flush() |
|---|
| 278 | file.close() |
|---|
| 279 | try: |
|---|
| 280 | if os.name == 'nt': |
|---|
| 281 | # CREATE_NO_WINDOW |
|---|
| 282 | p = Popen(['latex', '--interaction=nonstopmode', tmpfile + '.tex'], |
|---|
| 283 | creationflags=0x08000000, cwd=gettempdir()) |
|---|
| 284 | else: |
|---|
| 285 | p = Popen(['latex', '--interaction=nonstopmode', tmpfile + '.tex'], |
|---|
| 286 | cwd=gettempdir()) |
|---|
| 287 | exitcode = p.wait() |
|---|
| 288 | except Exception: |
|---|
| 289 | exitcode = 1 |
|---|
| 290 | if exitcode == 0: |
|---|
| 291 | try: |
|---|
| 292 | if os.name == 'nt': |
|---|
| 293 | # CREATE_NO_WINDOW |
|---|
| 294 | p = Popen(['dvipng', '-bg', 'white', '-T', 'tight', |
|---|
| 295 | tmpfile + '.dvi', '-o', tmpfile + '.png'], |
|---|
| 296 | creationflags=0x08000000, cwd=gettempdir()) |
|---|
| 297 | else: |
|---|
| 298 | p = Popen(['dvipng', '-bg', 'white', '-T', 'tight', |
|---|
| 299 | tmpfile + '.dvi', '-o', tmpfile + '.png'], cwd=gettempdir()) |
|---|
| 300 | exitcode = p.wait() |
|---|
| 301 | except Exception: |
|---|
| 302 | exitcode = 1 |
|---|
| 303 | extensions = ['.tex', '.log', '.aux', '.dvi', '.png'] |
|---|
| 304 | for ext in extensions: |
|---|
| 305 | try: |
|---|
| 306 | os.remove(tmpfile + ext) |
|---|
| 307 | except Exception: |
|---|
| 308 | pass |
|---|
| 309 | if exitcode == 0: |
|---|
| 310 | return True |
|---|
| 311 | return False |
|---|
| 312 | |
|---|
| 313 | def pycrypto_available(self): |
|---|
| 314 | from common import gajim |
|---|
| 315 | return gajim.HAVE_PYCRYPTO |
|---|
| 316 | |
|---|
| 317 | def docutils_available(self): |
|---|
| 318 | try: |
|---|
| 319 | import docutils |
|---|
| 320 | except Exception: |
|---|
| 321 | return False |
|---|
| 322 | return True |
|---|
| 323 | |
|---|
| 324 | def pysexy_available(self): |
|---|
| 325 | from common import gajim |
|---|
| 326 | return gajim.HAVE_PYSEXY |
|---|
| 327 | |
|---|
| 328 | # vim: se ts=3: |
|---|