PageRenderTime 26ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/modpython/znc.py

https://github.com/flakes/znc
Python | 371 lines | 362 code | 2 blank | 7 comment | 3 complexity | 79a9d9a6fefd3ddfbf0c0569238b6309 MD5 | raw file
  1. #
  2. # Copyright (C) 2004-2011 See the AUTHORS file for details.
  3. #
  4. # This program is free software; you can redistribute it and/or modify it
  5. # under the terms of the GNU General Public License version 2 as published
  6. # by the Free Software Foundation.
  7. #
  8. from znc_core import *
  9. import imp
  10. import re
  11. import traceback
  12. import collections
  13. class Socket:
  14. def _Accepted(self, host, port):
  15. psock = self.OnAccepted(host, port)
  16. print(psock)
  17. try:
  18. return psock._csock
  19. except AttributeError:
  20. return None
  21. def GetModule(self):
  22. return AsPyModule(self._csock.GetModule()).GetNewPyObj()
  23. def Listen(self, addrtype='all', port=None, bindhost='', ssl=False, maxconns=GetSOMAXCONN(), timeout=0):
  24. addr = ADDR_ALL
  25. addrtype = addrtype.lower()
  26. if addrtype == 'ipv4':
  27. addr = ADDR_IPV4ONLY
  28. elif addrtype == 'ipv6':
  29. addr = ADDR_IPV6ONLY
  30. elif addrtype != 'all':
  31. raise ValueError("Specified addrtype [{0}] isn't supported".format(addrtype))
  32. if port is None:
  33. return self.GetModule().GetManager().ListenRand(
  34. "python socket for {0}".format(self.GetModule().GetModName()),
  35. bindhost,
  36. ssl,
  37. maxconns,
  38. self._csock,
  39. timeout,
  40. addr
  41. )
  42. if self.GetModule().GetManager().ListenHost(
  43. port,
  44. 'python socket for {0}'.format(self.GetModule().GetModName()),
  45. bindhost,
  46. ssl,
  47. maxconns,
  48. self._csock,
  49. timeout,
  50. addr):
  51. return port
  52. return 0
  53. def Connect(self, host, port, timeout=60, ssl=False, bindhost=''):
  54. return self.GetModule().GetManager().Connect(
  55. host,
  56. port,
  57. 'python conn socket for {0}'.format(self.GetModule().GetModName()),
  58. timeout,
  59. ssl,
  60. bindhost,
  61. self._csock)
  62. def Write(self, data):
  63. if (isinstance(data, str)):
  64. return self._csock.Write(data)
  65. raise TypeError('socket.Write needs str. If you want binary data, use WriteBytes')
  66. def Init(self, *a, **b): pass
  67. def OnConnected(self): pass
  68. def OnDisconnected(self): pass
  69. def OnTimeout(self): pass
  70. def OnConnectionRefused(self): pass
  71. def OnReadData(self, bytess): pass
  72. def OnReadLine(self, line): pass
  73. def OnAccepted(self, host, port): pass
  74. def OnShutdown(self): pass
  75. class Timer:
  76. def GetModule(self):
  77. return AsPyModule(self._ctimer.GetModule()).GetNewPyObj()
  78. def RunJob(self): pass
  79. def OnShutdown(self): pass
  80. class ModuleNVIter(collections.Iterator):
  81. def __init__(self, cmod):
  82. self._cmod = cmod
  83. self.it = cmod.BeginNV_()
  84. def __next__(self):
  85. if self.it.is_end(self._cmod):
  86. raise StopIteration
  87. res = self.it.get()
  88. self.it.plusplus()
  89. return res
  90. class ModuleNV(collections.MutableMapping):
  91. def __init__(self, cmod):
  92. self._cmod = cmod
  93. def __setitem__(self, key, value):
  94. self._cmod.SetNV(key, value)
  95. def __getitem__(self, key):
  96. if not self._cmod.ExistsNV(key):
  97. raise KeyError
  98. return self._cmod.GetNV(key)
  99. def __contains__(self, key):
  100. return self._cmod.ExistsNV(key)
  101. def __delitem__(self, key):
  102. self._cmod.DelNV(key)
  103. def keys(self):
  104. return ModuleNVIter(self._cmod)
  105. __iter__ = keys
  106. def __len__(self):
  107. raise NotImplemented
  108. class Module:
  109. def OnLoad(self, sArgs, sMessage):
  110. return True
  111. def _GetSubPages(self):
  112. return self.GetSubPages()
  113. def CreateSocket(self, socketclass, *the, **rest):
  114. socket = socketclass()
  115. socket._csock = CreatePySocket(self._cmod, socket)
  116. socket.Init(*the, **rest)
  117. return socket
  118. def CreateTimer(self, timer, interval=10, cycles=1, label='pytimer', description='Some python timer'):
  119. t = timer()
  120. t._ctimer = CreatePyTimer(self._cmod, interval, cycles, label, description, t)
  121. return t
  122. def GetSubPages(self): pass
  123. def OnShutdown(self): pass
  124. def OnBoot(self): pass
  125. def WebRequiresLogin(self): pass
  126. def WebRequiresAdmin(self): pass
  127. def GetWebMenuTitle(self): pass
  128. def OnWebPreRequest(self, WebSock, sPageName): pass
  129. def OnWebRequest(self, WebSock, sPageName, Tmpl): pass
  130. def OnPreRehash(self): pass
  131. def OnPostRehash(self): pass
  132. def OnIRCDisconnected(self): pass
  133. def OnIRCConnected(self): pass
  134. def OnIRCConnecting(self, IRCSock): pass
  135. def OnIRCRegistration(self, sPass, sNick, sIdent, sRealName): pass
  136. def OnBroadcast(self, sMessage): pass
  137. def OnConfigLine(self, sName, sValue, pUser, pChan): pass
  138. def OnWriteUserConfig(self, Config): pass
  139. def OnWriteChanConfig(self, Config, Chan): pass
  140. def OnDCCUserSend(self, RemoteNick, uLongIP, uPort, sFile, uFileSize): pass
  141. def OnChanPermission(self, OpNick, Nick, Channel, uMode, bAdded, bNoChange): pass
  142. def OnOp(self, OpNick, Nick, Channel, bNoChange): pass
  143. def OnDeop(self, OpNick, Nick, Channel, bNoChange): pass
  144. def OnVoice(self, OpNick, Nick, Channel, bNoChange): pass
  145. def OnDevoice(self, OpNick, Nick, Channel, bNoChange): pass
  146. def OnMode(self, OpNick, Channel, uMode, sArg, bAdded, bNoChange): pass
  147. def OnRawMode(self, OpNick, Channel, sModes, sArgs): pass
  148. def OnRaw(self, sLine): pass
  149. def OnStatusCommand(self, sCommand): pass
  150. def OnModCommand(self, sCommand): pass
  151. def OnModNotice(self, sMessage): pass
  152. def OnModCTCP(self, sMessage): pass
  153. def OnQuit(self, Nick, sMessage, vChans): pass
  154. def OnNick(self, Nick, sNewNick, vChans): pass
  155. def OnKick(self, OpNick, sKickedNick, Channel, sMessage): pass
  156. def OnJoin(self, Nick, Channel): pass
  157. def OnPart(self, Nick, Channel, sMessage=None): pass
  158. def OnChanBufferStarting(self, Chan, Client): pass
  159. def OnChanBufferEnding(self, Chan, Client): pass
  160. def OnChanBufferPlayLine(self, Chan, Client, sLine): pass
  161. def OnPrivBufferPlayLine(self, Client, sLine): pass
  162. def OnClientLogin(self): pass
  163. def OnClientDisconnect(self): pass
  164. def OnUserRaw(self, sLine): pass
  165. def OnUserCTCPReply(self, sTarget, sMessage): pass
  166. def OnUserCTCP(self, sTarget, sMessage): pass
  167. def OnUserAction(self, sTarget, sMessage): pass
  168. def OnUserMsg(self, sTarget, sMessage): pass
  169. def OnUserNotice(self, sTarget, sMessage): pass
  170. def OnUserJoin(self, sChannel, sKey): pass
  171. def OnUserPart(self, sChannel, sMessage): pass
  172. def OnUserTopic(self, sChannel, sTopic): pass
  173. def OnUserTopicRequest(self, sChannel): pass
  174. def OnCTCPReply(self, Nick, sMessage): pass
  175. def OnPrivCTCP(self, Nick, sMessage): pass
  176. def OnChanCTCP(self, Nick, Channel, sMessage): pass
  177. def OnPrivAction(self, Nick, sMessage): pass
  178. def OnChanAction(self, Nick, Channel, sMessage): pass
  179. def OnPrivMsg(self, Nick, sMessage): pass
  180. def OnChanMsg(self, Nick, Channel, sMessage): pass
  181. def OnPrivNotice(self, Nick, sMessage): pass
  182. def OnChanNotice(self, Nick, Channel, sMessage): pass
  183. def OnTopic(self, Nick, Channel, sTopic): pass
  184. def OnServerCapAvailable(self, sCap): pass
  185. def OnServerCapResult(self, sCap, bSuccess): pass
  186. def OnTimerAutoJoin(self, Channel): pass
  187. def OnEmbeddedWebRequest(self, WebSock, sPageName, Tmpl): pass
  188. def make_inherit(cl, parent, attr):
  189. def make_caller(parent, name, attr):
  190. return lambda self, *a: parent.__dict__[name](self.__dict__[attr], *a)
  191. while True:
  192. for x in parent.__dict__:
  193. if x[:1] != '_' and x not in cl.__dict__:
  194. setattr(cl, x, make_caller(parent, x, attr))
  195. if '_s' in parent.__dict__:
  196. parent = parent._s
  197. else:
  198. break
  199. make_inherit(Socket, CPySocket, '_csock')
  200. make_inherit(Module, CPyModule, '_cmod')
  201. make_inherit(Timer, CPyTimer, '_ctimer')
  202. def find_open(modname):
  203. '''Returns (pymodule, datapath)'''
  204. for d in CModules.GetModDirs():
  205. # d == (libdir, datadir)
  206. try:
  207. x = imp.find_module(modname, [d[0]])
  208. except ImportError:
  209. # no such file in dir d
  210. continue
  211. # x == (<open file './modules/admin.so', mode 'rb' at 0x7fa2dc748d20>, './modules/admin.so', ('.so', 'rb', 3))
  212. # x == (<open file './modules/pythontest.py', mode 'U' at 0x7fa2dc748d20>, './modules/pythontest.py', ('.py', 'U', 1))
  213. if x[0] is None:
  214. # the same
  215. continue
  216. if x[2][0] == '.so':
  217. try:
  218. pymodule = imp.load_module(modname, *x)
  219. except ImportError:
  220. # found needed .so but can't load it...
  221. # maybe it's normal (non-python) znc module?
  222. # another option here could be to "continue"
  223. # search of python module in other moddirs.
  224. # but... we respect C++ modules ;)
  225. return (None, None)
  226. finally:
  227. x[0].close()
  228. else:
  229. # this is not .so, so it can be only python module .py or .pyc
  230. try:
  231. pymodule = imp.load_module(modname, *x)
  232. finally:
  233. x[0].close()
  234. return (pymodule, d[1])
  235. else:
  236. # nothing found
  237. return (None, None)
  238. def get_descr(cls):
  239. return getattr(cls, 'description', '< Placeholder for a description >')
  240. def load_module(modname, args, user, retmsg, modpython):
  241. '''Returns 0 if not found, 1 on loading error, 2 on success'''
  242. if re.search(r'[^a-zA-Z0-9_]', modname) is not None:
  243. retmsg.s = 'Module names can only contain letters, numbers and underscores, [{0}] is invalid.'.format(modname)
  244. return 1
  245. pymodule, datapath = find_open(modname)
  246. if pymodule is None:
  247. return 0
  248. if modname not in pymodule.__dict__:
  249. retmsg.s = "Python module [{0}] doesn't have class named [{1}]".format(pymodule.__file__, modname)
  250. return 1
  251. cl = pymodule.__dict__[modname]
  252. module = cl()
  253. module._cmod = CreatePyModule(user, modname, datapath, module, modpython)
  254. module.nv = ModuleNV(module._cmod)
  255. module.SetDescription(get_descr(cl))
  256. module.SetArgs(args)
  257. module.SetModPath(pymodule.__file__)
  258. user.GetModules().push_back(module._cmod)
  259. try:
  260. loaded = True
  261. if not module.OnLoad(args, retmsg):
  262. if retmsg.s == '':
  263. retmsg.s = 'Module [{0}] aborted.'.format(modname)
  264. else:
  265. retmsg.s = 'Module [{0}] aborted: {1}'.format(modname, retmsg.s)
  266. loaded = False
  267. except BaseException:
  268. if retmsg.s == '':
  269. retmsg.s = 'Got exception: {0}'.format(traceback.format_exc())
  270. else:
  271. retmsg.s = '{0}; Got exception: {1}'.format(retmsg.s, traceback.format_exc())
  272. loaded = False
  273. except:
  274. if retmsg.s == '':
  275. retmsg.s = 'Got exception.'
  276. else:
  277. retmsg.s = '{0}; Got exception.'.format(retmsg.s)
  278. loaded = False
  279. if loaded:
  280. if retmsg.s == '':
  281. retmsg.s = "Loaded module [{0}] [{1}]".format(modname, pymodule.__file__)
  282. else:
  283. retmsg.s = "Loaded module [{0}] [{2}] [{1}]".format(modname, pymodule.__file__, retmsg.s)
  284. return 2
  285. print(retmsg.s)
  286. unload_module(module)
  287. return 1
  288. def unload_module(module):
  289. module.OnShutdown()
  290. cmod = module._cmod
  291. del module._cmod
  292. cmod.GetUser().GetModules().removeModule(cmod)
  293. cmod.DeletePyModule()
  294. del cmod
  295. def get_mod_info(modname, retmsg, modinfo):
  296. '''0-not found, 1-error, 2-success'''
  297. pymodule, datadir = find_open(modname)
  298. if pymodule is None:
  299. return 0
  300. if modname not in pymodule.__dict__:
  301. retmsg.s = "Python module [{0}] doesn't have class named [{1}]".format(pymodule.__file__, modname)
  302. return 1
  303. cl = pymodule.__dict__[modname]
  304. modinfo.SetGlobal(False)
  305. modinfo.SetDescription(get_descr(cl))
  306. modinfo.SetName(modname)
  307. modinfo.SetPath(pymodule.__file__)
  308. return 2
  309. def get_mod_info_path(path, modname, modinfo):
  310. try:
  311. x = imp.find_module(modname, [path])
  312. except ImportError:
  313. return 0
  314. # x == (<open file './modules/admin.so', mode 'rb' at 0x7fa2dc748d20>, './modules/admin.so', ('.so', 'rb', 3))
  315. # x == (<open file './modules/pythontest.py', mode 'U' at 0x7fa2dc748d20>, './modules/pythontest.py', ('.py', 'U', 1))
  316. if x[0] is None:
  317. return 0
  318. try:
  319. pymodule = imp.load_module(modname, *x)
  320. except ImportError:
  321. return 0
  322. finally:
  323. x[0].close()
  324. if modname not in pymodule.__dict__:
  325. return 0
  326. cl = pymodule.__dict__[modname]
  327. modinfo.SetGlobal(False)
  328. modinfo.SetDescription(get_descr(cl))
  329. modinfo.SetName(modname)
  330. modinfo.SetPath(pymodule.__file__)
  331. return 1
  332. CONTINUE = CModule.CONTINUE
  333. HALT = CModule.HALT
  334. HALTMODS = CModule.HALTMODS
  335. HALTCORE = CModule.HALTCORE
  336. UNLOAD = CModule.UNLOAD
  337. HaveSSL = HaveSSL_()
  338. HaveCAres = HaveCAres_()
  339. HaveIPv6 = HaveIPv6_()
  340. Version = GetVersion()
  341. VersionMajor = GetVersionMajor()
  342. VersionMinor = GetVersionMinor()
  343. VersionExtra = GetVersionExtra()
  344. def CreateWebSubPage(name, title='', params=dict(), admin=False):
  345. vpair = VPair()
  346. for k, v in params.items():
  347. VPair_Add2Str_(vpair, k, v)
  348. flags = 0
  349. if admin:
  350. flags |= CWebSubPage.F_ADMIN
  351. return CreateWebSubPage_(name, title, vpair, flags)