暂无描述
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. import configparser
  4. import logging
  5. from sys import argv
  6. from threading import Thread
  7. from time import sleep
  8. from xml.dom import minidom
  9. import sleekxmpp
  10. import telegram
  11. from sleekxmpp.xmlstream.stanzabase import ElementBase
  12. from telegram.error import NetworkError, Unauthorized
  13. try:
  14. import requests
  15. except:
  16. logging.error("HTTP Upload support disabled.")
  17. class Request(ElementBase):
  18. """Special class to create http_upload requests."""
  19. namespace = 'urn:xmpp:http:upload'
  20. name = 'request'
  21. plugin_attrib = 'request'
  22. interfaces = set(('filename', 'size'))
  23. sub_interfaces = interfaces
  24. class Jabbergram(sleekxmpp.ClientXMPP):
  25. """Main object."""
  26. def __init__(self, jid, password, rooms, nick, token, groups, verify_ssl):
  27. """
  28. Executed when the class is initialized. It adds session handlers, muc
  29. handlers and send the telegram reading function and the HTTP upload
  30. initializing functions to their respective threads.
  31. """
  32. # XMPP
  33. super(Jabbergram, self).__init__(jid, password)
  34. self.add_event_handler('session_start', self.start)
  35. self.add_event_handler('groupchat_message', self.muc_message)
  36. self.muc_rooms = rooms.split()
  37. self.nick = nick
  38. self.token = token
  39. self.xmpp_users = {}
  40. self.jid = jid
  41. self.verify_ssl = verify_ssl
  42. for muc in self.muc_rooms:
  43. self.add_event_handler("muc::%s::got_online" % muc,
  44. self.muc_online)
  45. self.add_event_handler("muc::%s::got_offline" % muc,
  46. self.muc_offline)
  47. # Telegram
  48. self.groups = groups.split()
  49. self.bot = telegram.Bot(self.token)
  50. self.telegram_users = {}
  51. # initialize http upload on a thread since its needed to be connected
  52. # to xmpp
  53. t = Thread(target=self.init_http)
  54. t.daemon = True
  55. t.start()
  56. # put tg connector in a thread
  57. t = Thread(target=self.read_tg)
  58. t.daemon = True
  59. t.start()
  60. print('Please wait a couple of minutes until it\'s correctly '
  61. 'connected')
  62. def init_http(self):
  63. """
  64. Initializes HTTP upload support. Sends a discovery stanza to the server
  65. to find the HTTP upload component and asks for the max size a file can
  66. be.
  67. """
  68. self.http_upload = self.HttpUpload(self)
  69. self.component = self.http_upload.discovery()
  70. if self.component:
  71. xml = self.http_upload.disco_info(self.component)
  72. xml = minidom.parseString(str(xml))
  73. self.max_size = int(xml.getElementsByTagName('value')
  74. [1].firstChild.data)
  75. else:
  76. try:
  77. self.component = self.jid.split('@')[1]
  78. xml = self.http_upload.disco_info(self.component)
  79. xml = minidom.parseString(str(xml))
  80. self.max_size = int(xml.getElementsByTagName('value')
  81. [1].firstChild.data)
  82. except:
  83. self.max_size = None
  84. def read_tg(self):
  85. """Main telegram function."""
  86. update_id = 0
  87. # wait until http_upload has been tested
  88. sleep(5)
  89. while True:
  90. try:
  91. for update in self.bot.getUpdates(offset=update_id,
  92. timeout=10):
  93. name = ''
  94. size = 0
  95. if update.edited_message:
  96. update_id = update.update_id + 1
  97. continue
  98. if update.message.from_user:
  99. user = update.message.from_user.username
  100. # sometimes there's no user. weird, but it happens
  101. if not user:
  102. user = update.message.from_user.first_name
  103. # sometimes there's no user. weird, but it happens
  104. elif update.message['from']:
  105. user = str(update.message['from'].first_name)
  106. if update.message.audio or update.message.document or \
  107. update.message.photo or update.message.video \
  108. or update.message.voice or update.message.sticker:
  109. # proceed only if http upload is available
  110. if self.max_size is not None:
  111. if update.message.audio:
  112. d_file = update.message.audio
  113. ext = '.ogg'
  114. size = d_file.file_size
  115. elif update.message.document:
  116. d_file = update.message.document
  117. ext = ''
  118. size = d_file.file_size
  119. elif update.message.photo:
  120. d_file = update.message.photo[-1]
  121. ext = '.jpg'
  122. size = d_file.file_size
  123. elif update.message.video:
  124. d_file = update.message.video[-1]
  125. ext = '.mp4'
  126. size = d_file.file_size
  127. elif update.message.voice:
  128. d_file = update.message.voice
  129. ext = '.ogg'
  130. size = d_file.file_size
  131. elif update.message.sticker:
  132. d_file = update.message.sticker
  133. ext = '.png'
  134. size = d_file.file_size
  135. if self.max_size >= int(size):
  136. t_file = self.bot.getFile(d_file.file_id)
  137. f_name = '/tmp/' + d_file.file_id + ext
  138. t_file.download(f_name)
  139. url = self.http_upload.upload(
  140. self.component,
  141. self.verify_ssl,
  142. f_name, size)
  143. if update.message.caption:
  144. message = update.message.caption + ' '
  145. else:
  146. message = 'File uploaded: '
  147. message += url
  148. else:
  149. message = 'A file has been uploaded to Telegr'\
  150. 'am, but is too big.'
  151. else:
  152. message = 'A file has been uploaded to Telegram,'\
  153. 'but the XMPP server doesn\'t support H'\
  154. 'TTP Upload.'
  155. elif update.message.new_chat_members:
  156. message = 'This user has joined the group.'
  157. elif update.message.left_chat_member:
  158. message = 'This user has left the group.'
  159. elif update.message.new_chat_title:
  160. message = 'The group\'s title has changed: ' + \
  161. update.message.new_chat_title
  162. elif update.message.new_chat_photo:
  163. message = 'The group\'s photo has changed.'
  164. else:
  165. if update.message.reply_to_message:
  166. name = update.message.reply_to_message.from_user\
  167. .username
  168. if name != self.bot.username:
  169. message = name + ': ' + \
  170. update.message.reply_to_message.text
  171. else:
  172. message = update.message.reply_to_message.text
  173. else:
  174. message = update.message.text
  175. if name:
  176. msg = message + ' <- ' + user + ": " + \
  177. update.message.text
  178. else:
  179. msg = user + ": " + message
  180. if update.message.chat.type == 'supergroup' and \
  181. update.message.chat.username:
  182. chat = '@' + update.message.chat.username
  183. else:
  184. chat = str(update.message.chat.id)
  185. if chat not in self.groups:
  186. chat = str(update.message.chat_id)
  187. if message and chat in self.groups:
  188. index = self.groups.index(chat)
  189. receiver = self.muc_rooms[index]
  190. if chat in self.telegram_users:
  191. if user not in self.telegram_users[chat]:
  192. self.telegram_users[chat] += ' ' + user
  193. else:
  194. self.telegram_users[chat] = ' ' + user
  195. if message == '.users':
  196. self.say_users('telegram', receiver, chat)
  197. elif message == '.help':
  198. self.say_help('telegram', receiver, chat)
  199. elif message == '.where':
  200. self.say_where('telegram', receiver, chat)
  201. else:
  202. self.send_message(mto=receiver, mbody=msg,
  203. mtype='groupchat')
  204. update_id = update.update_id + 1
  205. except NetworkError as e:
  206. print(e)
  207. sleep(1)
  208. except Unauthorized as e:
  209. print(e)
  210. sleep(1)
  211. except Exception as e:
  212. update_id += 1
  213. print(e)
  214. def start(self, event):
  215. """Does some initial setup for XMPP and joins all mucs."""
  216. self.get_roster()
  217. self.send_presence()
  218. for muc in self.muc_rooms:
  219. self.plugin['xep_0045'].joinMUC(muc, self.nick, wait=True)
  220. def muc_message(self, msg):
  221. """Muc message's handler."""
  222. muc_room = str(msg['from']).split('/')[0]
  223. index = self.muc_rooms.index(muc_room)
  224. tg_group = self.groups[index]
  225. if msg['body'] == '.users':
  226. self.say_users('xmpp', muc_room, tg_group)
  227. elif msg['body'] == '.help':
  228. self.say_help('xmpp', muc_room, tg_group)
  229. elif msg['body'] == '.where':
  230. self.say_where('xmpp', muc_room, tg_group)
  231. elif msg['mucnick'] != self.nick:
  232. message = str(msg['from']).split('/')[1] + ': ' + str(msg['body'])
  233. self.bot.sendMessage(tg_group, text=message)
  234. def muc_online(self, presence):
  235. """Muc presence's handler."""
  236. user = presence['muc']['nick']
  237. muc = presence['from'].bare
  238. if user != self.nick:
  239. if muc in self.xmpp_users:
  240. self.xmpp_users[muc].append(presence['muc']['nick'])
  241. else:
  242. self.xmpp_users[muc] = [presence['muc']['nick']]
  243. def muc_offline(self, presence):
  244. """Muc presence's handler."""
  245. user = presence['muc']['nick']
  246. muc = presence['from'].bare
  247. if user != self.nick:
  248. self.xmpp_users[muc].remove(presence['muc']['nick'])
  249. def say_users(self, service, muc, group):
  250. """It returns the users on XMPP or Telegram."""
  251. if service == 'xmpp':
  252. if group in self.telegram_users:
  253. tg_users = self.telegram_users[group]
  254. else:
  255. tg_users = ""
  256. msg = 'Telegram Users:' + tg_users
  257. self.send_message(mto=muc, mbody=msg, mtype='groupchat')
  258. elif service == 'telegram':
  259. xmpp_users = ""
  260. if muc in self.xmpp_users:
  261. for i in self.xmpp_users[muc]:
  262. xmpp_users = xmpp_users + ' ' + i
  263. else:
  264. xmpp_users = ""
  265. msg = 'XMPP Users:' + xmpp_users
  266. self.bot.sendMessage(group, text=msg)
  267. def say_help(self, service, muc, group):
  268. """Help command."""
  269. msg = 'Hi, I\'m ' + self.bot.username + '. I have two commands : ".us'\
  270. 'ers" and ".where".'
  271. if service == 'xmpp':
  272. self.send_message(mto=muc, mbody=msg, mtype='groupchat')
  273. elif service == 'telegram':
  274. self.bot.sendMessage(group, text=msg)
  275. def say_where(self, service, muc, group):
  276. """Returns Telegram's group location if it's public."""
  277. if service == 'xmpp':
  278. if '@' in group:
  279. msg = 'I\'m on http://telegram.me/' + group.split('@')[1] + '.'
  280. else:
  281. msg = 'Sorry, I\'m on a private group, you\'ll have to ask fo'\
  282. 'r an invitation.'
  283. self.send_message(mto=muc, mbody=msg, mtype='groupchat')
  284. elif service == 'telegram':
  285. msg = 'I\'m on ' + muc + '.'
  286. self.bot.sendMessage(group, text=msg)
  287. class HttpUpload():
  288. """HTTP upload main class."""
  289. def __init__(self, parent_self):
  290. """Init... Yep."""
  291. self.parent_self = parent_self
  292. def discovery(self):
  293. """Discovers all server's components."""
  294. disco = sleekxmpp.basexmpp.BaseXMPP.Iq(self.parent_self)
  295. disco['query'] = "http://jabber.org/protocol/disco#items"
  296. disco['type'] = 'get'
  297. disco['from'] = self.parent_self.jid
  298. disco['to'] = self.parent_self.jid.split('@')[1]
  299. d = disco.send(timeout=30)
  300. xml = minidom.parseString(str(d))
  301. item = xml.getElementsByTagName('item')
  302. for component in item:
  303. component = component.getAttribute('jid')
  304. info = self.disco_info(component)
  305. if "urn:xmpp:http:upload" in info:
  306. http_upload_component = component
  307. break
  308. else:
  309. http_upload_component = ""
  310. return http_upload_component
  311. def disco_info(self, component):
  312. """Discovers HTTP upload components attributes."""
  313. info = sleekxmpp.basexmpp.BaseXMPP.Iq(self.parent_self)
  314. info['query'] = "http://jabber.org/protocol/disco#info"
  315. info['type'] = 'get'
  316. info['from'] = self.parent_self.jid
  317. info['to'] = component
  318. response = str(info.send(timeout=30))
  319. return response
  320. def upload(self, component, verify_ssl, u_file, size):
  321. """Uploads to HTTP upload."""
  322. peticion = Request()
  323. peticion['filename'] = u_file.split('/')[-1]
  324. peticion['size'] = str(size)
  325. iq = sleekxmpp.basexmpp.BaseXMPP.Iq(self.parent_self)
  326. iq.set_payload(peticion)
  327. iq['type'] = 'get'
  328. iq['to'] = component
  329. iq['from'] = self.parent_self.jid
  330. send = iq.send(timeout=30)
  331. xml = minidom.parseString(str(send))
  332. put_url = xml.getElementsByTagName('put')[0].firstChild.data
  333. if verify_ssl == 'False':
  334. req = requests.put(put_url, data=open(u_file, 'rb'),
  335. verify=False)
  336. else:
  337. req = requests.put(put_url, data=open(u_file, 'rb'))
  338. return put_url
  339. if __name__ == '__main__':
  340. # parse config
  341. config = []
  342. parser = configparser.SafeConfigParser()
  343. if len(argv) == 2:
  344. parser.read(argv[1])
  345. else:
  346. parser.read('config.ini')
  347. for name, value in parser.items('config'):
  348. config.append(value)
  349. # assign values for the bot
  350. jid = config[0]
  351. password = config[1]
  352. muc_rooms = config[2]
  353. nick = config[3]
  354. token = config[4]
  355. groups = config[5]
  356. verify_ssl = config[6]
  357. xmpp = Jabbergram(jid, password, muc_rooms, nick, token, groups,
  358. verify_ssl)
  359. xmpp.register_plugin('xep_0045')
  360. if xmpp.connect():
  361. xmpp.process(block=True)
  362. print("Done")
  363. else:
  364. print("Unable to connect.")