diff --git a/src/common/exceptions.py b/src/common/exceptions.py
index f91f600a3990b34d4b108b62b3e4e8857bb44e6e..9f20e1d9770b4d0efcab777c5c35403713d1ea5f 100644
--- a/src/common/exceptions.py
+++ b/src/common/exceptions.py
@@ -83,7 +83,7 @@ class Cancelled(Exception):
 	pass
 
 class LatexError(Exception):
-	'''sqlite2 raised pysqlite2.dbapi2.OperationalError'''
+	'''LaTeX processing failed for some reason'''
 	def __init__(self, text=''):
 		Exception.__init__(self)
 		self.text = text
diff --git a/src/common/gajim.py b/src/common/gajim.py
index e5a61147089bb22be2ceffc80c125b68838db010..89a72be32538bfcdf09c81833b9624ba5d4c9d30 100644
--- a/src/common/gajim.py
+++ b/src/common/gajim.py
@@ -176,64 +176,8 @@ else:
 	if system('gpg -h >/dev/null 2>&1'):
 		HAVE_GPG = False
 
-import os
-import random
-from tempfile import gettempdir
-from subprocess import Popen
-
-def check_for_latex_support():
-	'''check is latex is available and if it can create a picture.'''
-
-	exitcode = 0
-	random.seed()
-	tmpfile = os.path.join(gettempdir(), "gajimtex_" + \
-		random.randint(0,100).__str__())
-
-	# build latex string
-	texstr = '\\documentclass[12pt]{article}\\usepackage[dvips]{graphicx}'
-	texstr += '\\usepackage{amsmath}\\usepackage{amssymb}\\pagestyle{empty}'
-	texstr += '\\begin{document}\\begin{large}\\begin{gather*}test'
-	texstr += '\\end{gather*}\\end{large}\\end{document}'
-
-	file_ = open(os.path.join(tmpfile + ".tex"), "w+")
-	file_.write(texstr)
-	file_.flush()
-	file_.close()
-	try:
-		if os.name == 'nt':
-			# CREATE_NO_WINDOW
-			p = Popen(['latex', '--interaction=nonstopmode', tmpfile + '.tex'],
-				creationflags=0x08000000, cwd=gettempdir())
-		else:
-			p = Popen(['latex', '--interaction=nonstopmode', tmpfile + '.tex'],
-				cwd=gettempdir())
-		exitcode = p.wait()
-	except Exception:
-		exitcode = 1
-	if exitcode == 0:
-		try:
-			if os.name == 'nt':
-				# CREATE_NO_WINDOW
-				p = Popen(['dvipng', '-bg', 'white', '-T', 'tight',
-					tmpfile + '.dvi', '-o', tmpfile + '.png'],
-					creationflags=0x08000000, cwd=gettempdir())
-			else:
-				p = Popen(['dvipng', '-bg', 'white', '-T', 'tight',
-					tmpfile + '.dvi', '-o', tmpfile + '.png'], cwd=gettempdir())
-			exitcode = p.wait()
-		except Exception:
-			exitcode = 1
-	extensions = ['.tex', '.log', '.aux', '.dvi', '.png']
-	for ext in extensions:
-		try:
-			os.remove(tmpfile + ext)
-		except Exception:
-			pass
-	if exitcode == 0:
-		return True
-	return False
-
-HAVE_LATEX = check_for_latex_support()
+import latex
+HAVE_LATEX = latex.check_for_latex_support()
 
 gajim_identity = {'type': 'pc', 'category': 'client', 'name': 'Gajim'}
 gajim_common_features = [xmpp.NS_BYTESTREAM, xmpp.NS_SI, xmpp.NS_FILE,
diff --git a/src/common/latex.py b/src/common/latex.py
new file mode 100644
index 0000000000000000000000000000000000000000..fb1a57799d235e4ef427f473e9032ffb08f600ca
--- /dev/null
+++ b/src/common/latex.py
@@ -0,0 +1,148 @@
+# -*- coding:utf-8 -*-
+## src/common/latex.py
+##
+## Copyright (C) 2005 Norman Rasmussen <norman AT rasmussen.co.za>
+## Copyright (C) 2005-2006 Alex Mauer <hawke AT hawkesnest.net>
+##                         Travis Shirk <travis AT pobox.com>
+## Copyright (C) 2005-2007 Nikos Kouremenos <kourem AT gmail.com>
+## Copyright (C) 2005-2008 Yann Leboulanger <asterix AT lagaule.org>
+## Copyright (C) 2006 Dimitur Kirov <dkirov AT gmail.com>
+## Copyright (C) 2006-2008 Jean-Marie Traissard <jim AT lapin.org>
+## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org>
+##                    Julien Pivotto <roidelapluie AT gmail.com>
+##                    Stephan Erb <steve-e AT h3c.de>
+##
+## This file is part of Gajim.
+##
+## Gajim is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published
+## by the Free Software Foundation; version 3 only.
+##
+## Gajim is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
+##
+
+import os
+import random
+from tempfile import gettempdir
+from subprocess import Popen
+
+import gajim
+from exceptions import LatexError
+
+# some latex commands are really bad
+blacklist = ['\\def', '\\let', '\\futurelet',
+	'\\newcommand', '\\renewcomment', '\\else', '\\fi', '\\write',
+	'\\input', '\\include', '\\chardef', '\\catcode', '\\makeatletter',
+	'\\noexpand', '\\toksdef', '\\every', '\\errhelp', '\\errorstopmode',
+	'\\scrollmode', '\\nonstopmode', '\\batchmode', '\\read', '\\csname',
+	'\\newhelp', '\\relax', '\\afterground', '\\afterassignment',
+	'\\expandafter', '\\noexpand', '\\special', '\\command', '\\loop',
+	'\\repeat', '\\toks', '\\output', '\\line', '\\mathcode', '\\name',
+	'\\item', '\\section', '\\mbox', '\\DeclareRobustCommand', '\\[',
+	'\\]']
+# True if the string matches the blacklist
+def check_blacklist(str_):
+	for word in blacklist:
+		if word in str_:
+			return True
+	return False
+
+def get_tmpfile_name():
+	random.seed()
+	int_ = random.randint(0, 100)
+	return os.path.join(gettempdir(), 'gajimtex_' + int_.__str__())
+
+def write_latex(filename, str_):
+	texstr = '\\documentclass[12pt]{article}\\usepackage[dvips]{graphicx}'
+	texstr += '\\usepackage{amsmath}\\usepackage{amssymb}'
+	texstr += '\\pagestyle{empty}'
+	texstr += '\\begin{document}\\begin{large}\\begin{gather*}'
+	texstr += str_
+	texstr += '\\end{gather*}\\end{large}\\end{document}'
+
+	file_ = open(filename, "w+")
+	file_.write(texstr)
+	file_.flush()
+	file_.close()
+
+# a wrapper for Popen so that no window gets opened on Windows
+def popen_nt_friendly(command):
+	if os.name == 'nt':
+		# CREATE_NO_WINDOW
+		return Popen(command, creationflags=0x08000000, cwd=gettempdir())
+	else:
+		return Popen(command, cwd=gettempdir())
+
+def check_for_latex_support():
+	'''check is latex is available and if it can create a picture.'''
+
+	try:
+		filename = latex_to_image("test")
+		if filename:
+			# we have a file, conversion succeeded
+			os.remove(filename)
+			return True
+		return False
+	except LatexError:
+		return False
+
+def latex_to_image(str_):
+	result = None
+	exitcode = 0
+
+	# filter latex code with bad commands
+	if check_blacklist(str_):
+		# we triggered the blacklist, immediately return None
+		return None
+
+	tmpfile = get_tmpfile_name()
+
+	# build latex string
+	write_latex(os.path.join(tmpfile + '.tex'), str_)
+
+	# convert TeX to dvi
+	try:
+		p = popen_nt_friendly(['latex', '--interaction=nonstopmode',
+			tmpfile + '.tex'])
+		exitcode = p.wait()
+	except Exception, e:
+		exitcode = _('Error executing "%(command)s": %(error)s') % {
+			'command': 'latex --interaction=nonstopmode %s.tex' % tmpfile,
+			'error': str(e)}
+
+	if exitcode == 0:
+		# convert dvi to png
+		latex_png_dpi = gajim.config.get('latex_png_dpi')
+		try:
+			p = popen_nt_friendly(['dvipng', '-bg', 'rgb 1.0 1.0 1.0', '-T',
+				'tight', '-D', latex_png_dpi, tmpfile + '.dvi', '-o',
+				tmpfile + '.png'])
+			exitcode = p.wait()
+		except Exception, e:
+			exitcode = _('Error executing "%(command)s": %(error)s') % {
+				'command': 'dvipng -bg rgb 1.0 1.0 1.0 -T tight -D %s %s.dvi -o '
+				'%s.png' % (latex_png_dpi, tmpfile, tmpfile), 'error': str(e)}
+
+	# remove temp files created by us and TeX
+	extensions = ['.tex', '.log', '.aux', '.dvi']
+	for ext in extensions:
+		try:
+			os.remove(tmpfile + ext)
+		except Exception:
+			pass
+
+	if isinstance(exitcode, (unicode, str)):
+		raise LatexError(exitcode)
+
+	if exitcode == 0:
+		result = tmpfile + '.png'
+
+	return result
+
+# vim: se ts=3:
diff --git a/src/conversation_textview.py b/src/conversation_textview.py
index 227d7ff0e9f9652388f647c28ed90ce068d3cef8..95c0fa7189aa8bbdb88fa79eda7d183e4e668a05 100644
--- a/src/conversation_textview.py
+++ b/src/conversation_textview.py
@@ -27,9 +27,6 @@
 ## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
 ##
 
-import random
-from tempfile import gettempdir
-from subprocess import Popen
 from threading import Timer # for smooth scrolling
 
 import gtk
@@ -45,6 +42,7 @@ import Queue
 import gtkgui_helpers
 from common import gajim
 from common import helpers
+from common import latex
 from calendar import timegm
 from common.fuzzyclock import FuzzyClock
 
@@ -959,95 +957,6 @@ class ConversationTextview:
 
 		return index # the position after *last* special text
 
-	def latex_to_image(self, str_):
-		result = None
-		exitcode = 0
-
-		# some latex commands are really bad
-		blacklist = ['\\def', '\\let', '\\futurelet',
-			'\\newcommand', '\\renewcomment', '\\else', '\\fi', '\\write',
-			'\\input', '\\include', '\\chardef', '\\catcode', '\\makeatletter',
-			'\\noexpand', '\\toksdef', '\\every', '\\errhelp', '\\errorstopmode',
-			'\\scrollmode', '\\nonstopmode', '\\batchmode', '\\read', '\\csname',
-			'\\newhelp', '\\relax', '\\afterground', '\\afterassignment',
-			'\\expandafter', '\\noexpand', '\\special', '\\command', '\\loop',
-			'\\repeat', '\\toks', '\\output', '\\line', '\\mathcode', '\\name',
-			'\\item', '\\section', '\\mbox', '\\DeclareRobustCommand', '\\[',
-			'\\]']
-
-		str_ = str_[2:len(str_)-2]
-
-		# filter latex code with bad commands
-		for word in blacklist:
-			if word in str_:
-				exitcode = 1
-				break
-
-		if exitcode == 0:
-			random.seed()
-			tmpfile = os.path.join(gettempdir(), 'gajimtex_' + random.randint(0,
-				100).__str__())
-
-			# build latex string
-			texstr = '\\documentclass[12pt]{article}\\usepackage[dvips]{graphicx}'
-			texstr += '\\usepackage{amsmath}\\usepackage{amssymb}'
-			texstr += '\\pagestyle{empty}'
-			texstr += '\\begin{document}\\begin{large}\\begin{gather*}'
-			texstr += str_
-			texstr += '\\end{gather*}\\end{large}\\end{document}'
-
-			file_ = open(os.path.join(tmpfile + '.tex'), 'w+')
-			file_.write(texstr)
-			file_.flush()
-			file_.close()
-
-			try:
-				if os.name == 'nt':
-					# CREATE_NO_WINDOW
-					p = Popen(['latex', '--interaction=nonstopmode',
-						tmpfile + '.tex'], creationflags=0x08000000, cwd=gettempdir())
-				else:
-					p = Popen(['latex', '--interaction=nonstopmode',
-						tmpfile + '.tex'], cwd=gettempdir())
-				exitcode = p.wait()
-			except Exception, e:
-				exitcode = _('Error executing "%(command)s": %(error)s') % {
-					'command': 'latex --interaction=nonstopmode %s.tex' % tmpfile,
-					'error': str(e)}
-
-		if exitcode == 0:
-			latex_png_dpi = gajim.config.get('latex_png_dpi')
-			try:
-				if os.name == 'nt':
-					# CREATE_NO_WINDOW
-					p = Popen(['dvipng', '-bg', 'rgb 1.0 1.0 1.0', '-T', 'tight',
-						'-D', latex_png_dpi, tmpfile + '.dvi', '-o',
-						tmpfile + '.png'], creationflags=0x08000000, cwd=gettempdir())
-				else:
-					p = Popen(['dvipng', '-bg', 'rgb 1.0 1.0 1.0', '-T', 'tight',
-						'-D', latex_png_dpi, tmpfile + '.dvi', '-o',
-						tmpfile + '.png'], cwd=gettempdir())
-				exitcode = p.wait()
-			except Exception, e:
-				exitcode = _('Error executing "%(command)s": %(error)s') % {
-					'command': 'dvipng -bg rgb 1.0 1.0 1.0 -T tight -D %s %s.dvi -o '
-					'%s.png' % (latex_png_dpi, tmpfile, tmpfile), 'error': str(e)}
-
-		extensions = ['.tex', '.log', '.aux', '.dvi']
-		for ext in extensions:
-			try:
-				os.remove(tmpfile + ext)
-			except Exception:
-				pass
-
-		if isinstance(exitcode, (unicode, str)):
-			raise LatexError(exitcode)
-
-		if exitcode == 0:
-			result = tmpfile + '.png'
-
-		return result
-
 	def print_special_text(self, special_text, other_tags):
 		'''is called by detect_and_print_special_text and prints
 		special text (emots, links, formatting)'''
@@ -1144,7 +1053,7 @@ class ConversationTextview:
 		elif gajim.HAVE_LATEX and special_text.startswith('$$') and \
 		special_text.endswith('$$'):
 			try:
-				imagepath = self.latex_to_image(special_text)
+				imagepath = latex.latex_to_image(special_text[2:-2])
 			except LatexError, e:
 				# print the error after the line has been written
 				gobject.idle_add(self.print_conversation_line, str(e), '', 'info',