This file is indexed.

/usr/share/pymsnt/src/main.py is in pymsnt 0.11.3+hg224-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
# Copyright 2004-2006 James Bunton <james@delx.cjb.net>
# Licensed for distribution under the GPL version 2, check COPYING for details

import os, os.path, time, sys, codecs, getopt
reload(sys)
sys.setdefaultencoding("utf-8")
sys.stdout = codecs.lookup('utf-8')[-1](sys.stdout)


# Find the best reactor
selectWarning = "Unable to install any good reactors (kqueue, epoll, poll).\nWe fell back to using select. You may have scalability problems.\nThis reactor will not support more than 1024 connections at a time."
reactors = [("epollreactor", True), ("pollreactor", True), ("selectreactor", False), ("default", False)]
for tryReactor, good in reactors:
	try:
		bestReactor = __import__("twisted.internet." + tryReactor)
		if not good:
			print >> sys.stderr, selectWarning
		break
	except ImportError:
		pass
else:
	print >> sys.stderr, "Unable to find a reactor. Please make sure you have Twisted properly installed.\nExiting..."
	sys.exit(1)


import twistfix
twistfix.main()


# Must load config before everything else
import config
import xmlconfig
configFile = "config.xml"
configOptions = {}
opts, args = getopt.getopt(sys.argv[1:], "bc:o:dDgtlp:h", ["background", "config=", "option=", "debug", "Debug", "garbage", "traceback", "log=", "pid=", "help"])
for o, v in opts:
	if o in ("-c", "--config"):
		configFile = v
	elif o in ("-b", "--background"):
		config.background = True
	elif o in ("-d", "--debug"):
		config.debugLevel = "2"
	elif o in ("-D", "--Debug"):
		config.debugLevel = "3"
	elif o in ("-g", "--garbage"):
		import gc
		gc.set_debug(gc.DEBUG_LEAK|gc.DEBUG_STATS)
	elif o in ("-t", "--traceback"):
		config.debugLevel = "1"
	elif o in ("-l", "--log"):
		config.debugFile = v
	elif o in ("-p", "--pid"):
		config.pid = v
	elif o in ("-o", "--option"):
		var, setting = v.split("=", 2)
		configOptions[var] = setting
	elif o in ("-h", "--help"):
		print "%s [options]" % sys.argv[0]
		print "   -h                  print this help"
		print "   -b                  daemonize/background transport"
		print "   -c <file>           read configuration from this file"
		print "   -d                  print debugging output"
		print "   -D                  print extended debugging output"
		print "   -g                  print garbage collection output"
		print "   -t                  print debugging only on traceback"
		print "   -l <file>           write debugging output to file"
		print "   -p <file>           write process ID to file"
		print "   -o <var>=<setting>  set config var to setting"
		sys.exit(0)

xmlconfig.reloadConfig(configFile, configOptions)

if config.reactor:
	# They picked their own reactor. Lets install it.
	if sys.modules.has_key("twisted.internet.reactor"):
		del sys.modules["twisted.internet.reactor"]
	if config.reactor == "epoll":
		from twisted.internet import epollreactor
		epollreactor.install()
	elif config.reactor == "poll":
		from twisted.internet import pollreactor
		pollreactor.install()
	elif config.reactor == "kqueue":
		from twisted.internet import kqreactor
		kqreactor.install()
	elif len(config.reactor) > 0:
		print >> sys.stderr, "Unknown reactor: ", config.reactor, ". Using best available reactor."


from twisted.internet import reactor, task
from twisted.internet.defer import Deferred
from twisted.words.xish.domish import Element
from twisted.words.protocols.jabber import component
from twisted.words.protocols.jabber.jid import internJID

from debug import LogEvent, INFO, WARN, ERROR

import debug
import utils
import xdb
import avatar
import session
import jabw
import disco
import register
import misciq
import ft
import lang
import legacy
import housekeep



class PyTransport(component.Service):
	def __init__(self):
		LogEvent(INFO)
		LogEvent(INFO, msg="Reactor: " + str(reactor))

		# Discovery, as well as some builtin features
		self.discovery = disco.ServerDiscovery(self)
		self.discovery.addIdentity("gateway", legacy.id, config.discoName, config.jid)
		self.discovery.addIdentity("conference", "text", config.discoName + " Chatrooms", config.jid)
		self.discovery.addFeature(disco.XCONFERENCE, None, config.jid) # So that clients know you can create groupchat rooms on the server
		self.discovery.addFeature("jabber:iq:conference", None, config.jid) # We don't actually support this, but Psi has a bug where it looks for this instead of the above
		self.discovery.addIdentity("client", "pc", "MSN Messenger", "USER")
		self.discovery.addIdentity("conference", "text", "MSN Groupchat", "ROOM")
		
		self.xdb = xdb.XDB(config.jid, legacy.mangle)
		self.avatarCache = avatar.AvatarCache()
		self.registermanager = register.RegisterManager(self)
		self.gatewayTranslator = misciq.GatewayTranslator(self)
		self.versionTeller = misciq.VersionTeller(self)
		self.pingService = misciq.PingService(self)
		self.adHocCommands = misciq.AdHocCommands(self)
		self.vCardFactory = misciq.VCardFactory(self)
		self.iqAvatarFactor = misciq.IqAvatarFactory(self)
		self.connectUsers = misciq.ConnectUsers(self)
		if config.ftJabberPort:
			self.ftSOCKS5Receive = ft.Proxy65(int(config.ftJabberPort))
			self.ftSOCKS5Send = misciq.Socks5FileTransfer(self)
		if config.ftOOBPort:
			self.ftOOBReceive = ft.FileTransferOOBReceive(int(config.ftOOBPort))
			self.ftOOBSend = misciq.FileTransferOOBSend(self)
		self.statistics = misciq.Statistics(self)
		self.startTime = int(time.time())

		self.xmlstream = None
		self.sessions = {}
		
		# Groupchat ID handling
		self.lastID = 0
		self.reservedIDs = []

		# Message IDs
		self.messageID = 0
		
		self.loopTask = task.LoopingCall(self.loopFunc)
		self.loopTask.start(60.0)

	def removeMe(self):
		LogEvent(INFO)
		for session in self.sessions.copy():
			self.sessions[session].removeMe()
	
	def makeMessageID(self):
		self.messageID += 1
		return str(self.messageID)
	
	def makeID(self):
		newID = "r" + str(self.lastID)
		self.lastID += 1
		if self.reservedIDs.count(newID) > 0:
			# Ack, it's already used.. Try again
			return self.makeID()
		else:
			return newID
	
	def reserveID(self, ID):
		self.reservedIDs.append(ID)
	
	def loopFunc(self):
		numsessions = len(self.sessions)

		#if config.debugOn and numsessions > 0:
		#	print "Sessions:"
		#	for key in self.sessions:
		#		print "\t" + self.sessions[key].jabberID
	
		self.statistics.stats["Uptime"] = int(time.time()) - self.startTime
		self.statistics.stats["OnlineUsers"] = numsessions
		legacy.updateStats(self.statistics)
		if numsessions > 0:
			oldDict = self.sessions.copy()
			self.sessions = {}
			for key in oldDict:
				s = oldDict[key]
				if not s.alive:
					LogEvent(WARN, "", "Ghost session found.")
					# Don't add it to the new dictionary. Effectively removing it
				else:
					self.sessions[key] = s
	
	def componentConnected(self, xmlstream):
		LogEvent(INFO)
		self.xmlstream = xmlstream
		self.xmlstream.addObserver("/iq", self.discovery.onIq)
		self.xmlstream.addObserver("/presence", self.onPresence)
		self.xmlstream.addObserver("/message", self.onMessage)
		self.xmlstream.addObserver("/route", self.onRouteMessage)
		if config.useXCP:
			pres = Element((None, "presence"))
			pres.attributes["to"] = "presence@-internal"
			pres.attributes["from"] = config.compjid
			x = pres.addElement("x")
			x.attributes["xmlns"] = "http://www.jabber.com/schemas/component-presence.xsd"
			x.attributes["xmlns:config"] = "http://www.jabber.com/config"
			x.attributes["config:version"] = "1"
			x.attributes["protocol-version"] = "1.0"
			x.attributes["config-ns"] = legacy.url + "/component"
			self.send(pres)
		self.connectUsers.sendProbes() # A bit of a violation of encapsulation
	
	def componentDisconnected(self):
		LogEvent(INFO)
		self.xmlstream = None
	
	def onRouteMessage(self, el):
		for child in el.elements():
			if child.name == "message":
				self.onMessage(child)
			elif child.name == "presence":
				# Ignore any presence broadcasts about other XCP components
				if child.getAttribute("to") and child.getAttribute("to").find("@-internal") > 0: return
				self.onPresence(child)
			elif child.name == "iq":
				self.discovery.onIq(child)
	
	def onMessage(self, el):
		fro = el.getAttribute("from")
		try:
			froj = internJID(fro)
		except Exception, e:
			LogEvent(WARN, "", "Failed stringprep.")
			return
		mtype = el.getAttribute("type")
		s = self.sessions.get(froj.userhost(), None)
		if mtype == "error" and s:
			LogEvent(INFO, s.jabberID, "Removing session because of message type=error")
			s.removeMe()
		elif s:
			s.onMessage(el)
		elif mtype != "error":
			to = el.getAttribute("to")
			ulang = utils.getLang(el)
			body = None
			for child in el.elements():
				if child.name == "body":
					body = child.__str__()
			LogEvent(INFO, "", "Sending error response to a message outside of session.")
			jabw.sendErrorMessage(self, fro, to, "auth", "not-authorized", lang.get(ulang).notLoggedIn, body)
			jabw.sendPresence(self, fro, to, ptype="unavailable")
	
	def onPresence(self, el):
		fro = el.getAttribute("from")
		to = el.getAttribute("to")
		try:
			froj = internJID(fro)
			toj = internJID(to)
		except Exception, e:
			LogEvent(WARN, "", "Failed stringprep.")
			return

		ptype = el.getAttribute("type")
		s = self.sessions.get(froj.userhost())
		if ptype == "error" and s:
			LogEvent(INFO, s.jabberID, "Removing session because of message type=error")
			s.removeMe()
		elif s:
			s.onPresence(el)
		else:
			ulang = utils.getLang(el)
			ptype = el.getAttribute("type")
			if to.find('@') < 0:
				# If the presence packet is to the transport (not a user) and there isn't already a session
				if not el.getAttribute("type"): # Don't create a session unless they're sending available presence
					LogEvent(INFO, "", "Attempting to create a new session.")
					s = session.makeSession(self, froj.userhost(), ulang)
					if s:
						self.statistics.stats["TotalUsers"] += 1
						self.sessions[froj.userhost()] = s
						LogEvent(INFO, "", "New session created.")
						# Send the first presence
						s.onPresence(el)
					else:
						LogEvent(INFO, "", "Failed to create session")
						jabw.sendMessage(self, to=froj.userhost(), fro=config.jid, body=lang.get(ulang).notRegistered)
				
				elif el.getAttribute("type") != "error":
					LogEvent(INFO, "", "Sending unavailable presence to non-logged in user.")
					jabw.sendPresence(self, fro, to, ptype="unavailable")
					return
			
			elif ptype and (ptype.startswith("subscribe") or ptype.startswith("unsubscribe")):
				# They haven't logged in, and are trying to change subscription to a user
				# No, lets not log them in. Lets send an error :)
				jabw.sendPresence(self, fro, to, ptype="error")
				
				# Lets log them in and then do it
				#LogEvent(INFO, "", "Attempting to create a session to do subscription stuff.")
				#s = session.makeSession(self, froj.userhost(), ulang)
				#if s:
				#	self.sessions[froj.userhost()] = s
				#	LogEvent(INFO, "", "New session created.")
				#	# Tell the session there's a new resource
				#	s.handleResourcePresence(froj.userhost(), froj.resource, toj.userhost(), toj.resource, 0, None, None, None)
				#	# Send this subscription
				#	s.onPresence(el)


class App:
	def __init__(self):
		# Check for any other instances
		if config.pid and os.name != "posix":
			config.pid = ""
		if config.pid:
			twistd.checkPID(config.pid)

		# Do any auto-update stuff
		housekeep.init()
		
		# Daemonise the process and write the PID file
		if config.background and os.name == "posix":
			twistd.daemonize(reactor, os)
		if config.pid:
			self.writePID()

		# Initialise debugging, and do the other half of SIGHUPstuff
		debug.reloadConfig()
		legacy.reloadConfig()

		# Start the service
		jid = config.jid
		if config.useXCP and config.compjid:
			jid = config.compjid
		self.c = component.buildServiceManager(jid, config.secret, "tcp:%s:%s" % (config.mainServer, config.port))
		self.transportSvc = PyTransport()
		self.transportSvc.setServiceParent(self.c)
		self.c.startService()
		reactor.addSystemEventTrigger('before', 'shutdown', self.shuttingDown)
	
	def writePID(self):
		# Create a PID file
		pid = str(os.getpid())
		pf = open(config.pid, "w")
		pf.write("%s\n" % pid)
		pf.close()

	def removePID(self):
		try:
			os.unlink(config.pid)
		except OSError, e:
			if e.errno == errno.EACCES or e.errno == errno.EPERM:
				print "Warning: No permission to delete pid file"
			else:
				print "Failed to unlink PID file:"
				print e
		except:
			print "Failed to unlink PID file"

	def shuttingDown(self):
		self.transportSvc.removeMe()
		# Keep the transport running for another 3 seconds
		def cb(ignored=None):
			if config.pid:
				self.removePID()
		d = Deferred()
		d.addCallback(cb)
		reactor.callLater(3.0, d.callback, None)
		return d



def SIGHUPstuff(*args):
	global configFile, configOptions
	xmlconfig.reloadConfig(configFile, configOptions)
	if config.pid and os.name != "posix":
		config.pid = ""
	debug.reloadConfig()
	legacy.reloadConfig()

if os.name == "posix":
	import signal
	# Set SIGHUP to reload the config file & close & open debug file
	signal.signal(signal.SIGHUP, SIGHUPstuff)
	# Load some scripts for PID and daemonising
	from twisted.scripts import _twistd_unix as twistd


def main():
	# Create the application
	app = App()
	reactor.run()

if __name__ == "__main__":
	main()