Advertisement
Guest User

client.py

a guest
Jun 21st, 2017
662
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.20 KB | None | 0 0
  1. # -*- coding: utf-8 -*-
  2. """
  3. line.client
  4. ~~~~~~~~~~~
  5.  
  6. LineClient for sending and receiving message from LINE server.
  7.  
  8. :copyright: (c) 2014 by Taehoon Kim.
  9. :license: BSD, see LICENSE for more details.
  10. """
  11. import re
  12. import requests
  13. import sys
  14.  
  15. from api import LineAPI
  16. from models import LineGroup, LineContact, LineRoom, LineMessage
  17. from curve.ttypes import TalkException, ToType, OperationType, Provider
  18.  
  19. reload(sys)
  20. sys.setdefaultencoding("utf-8")
  21.  
  22. EMAIL_REGEX = re.compile(r"[^@]+@[^@]+\.[^@]+")
  23.  
  24. def check_auth(func):
  25. def wrapper_check_auth(*args, **kwargs):
  26. if args[0]._check_auth():
  27. return func(*args, **kwargs)
  28. return wrapper_check_auth
  29.  
  30. class LineClient(LineAPI):
  31. profile = None
  32. contacts = []
  33. rooms = []
  34. groups = []
  35.  
  36. def __init__(self, id=None, password=None, authToken=None, is_mac=True, com_name="carpedm20"):
  37. """Provide a way to communicate with LINE server.
  38.  
  39. :param id: `NAVER id` or `LINE email`
  40. :param password: LINE account password
  41. :param authToken: LINE session key
  42. :param is_mac: (optional) os setting
  43. :param com_name: (optional) name of your system
  44.  
  45. >>> client = LineClient("carpedm20", "xxxxxxxxxx")
  46. Enter PinCode '9779' to your mobile phone in 2 minutes
  47. >>> client = LineClient("carpedm20@gmail.com", "xxxxxxxxxx")
  48. Enter PinCode '7390' to your mobile phone in 2 minutes
  49. >>> client = LineClient(authToken="xxx ... xxx")
  50. True
  51. """
  52. LineAPI.__init__(self)
  53.  
  54. if not (authToken or id and password):
  55. msg = "id and password or authToken is needed"
  56. self.raise_error(msg)
  57.  
  58. if is_mac:
  59. os_version = "10.9.4-MAVERICKS-x64"
  60. user_agent = "DESKTOP:MAC:%s(%s)" % (os_version, self.version)
  61. app = "DESKTOPMAC\t%s\tMAC\t%s" % (self.version, os_version)
  62. else:
  63. os_version = "5.1.2600-XP-x64"
  64. user_agent = "DESKTOP:WIN:%s(%s)" % (os_version, self.version)
  65. app = "DESKTOPWIN\t%s\tWINDOWS\t%s" % (self.version, os_version)
  66.  
  67. if com_name:
  68. self.com_name = com_name
  69.  
  70. self._headers['User-Agent'] = user_agent
  71. self._headers['X-Line-Application'] = app
  72.  
  73. if authToken:
  74. self.authToken = self._headers['X-Line-Access'] = authToken
  75.  
  76. self.tokenLogin()
  77. #self.ready()
  78. else:
  79. if EMAIL_REGEX.match(id):
  80. self.provider = Provider.LINE # LINE
  81. else:
  82. self.provider = Provider.NAVER_KR # NAVER
  83.  
  84. self.id = id
  85. self.password = password
  86. self.is_mac = is_mac
  87.  
  88. self.login()
  89. self.ready()
  90.  
  91. self.revision = self._getLastOpRevision()
  92. self.getProfile()
  93.  
  94. try:
  95. self.refreshGroups()
  96. except: pass
  97.  
  98. try:
  99. self.refreshContacts()
  100. except: pass
  101.  
  102. try:
  103. self.refreshActiveRooms()
  104. except: pass
  105.  
  106. @check_auth
  107. def getProfile(self):
  108. """Get `profile` of LINE account"""
  109. self.profile = LineContact(self, self._getProfile())
  110.  
  111. return self.profile
  112.  
  113. def getContactByName(self, name):
  114. """Get a `contact` by name
  115.  
  116. :param name: name of a `contact`
  117. """
  118. for contact in self.contacts:
  119. if name == contact.name:
  120. return contact
  121.  
  122. return None
  123.  
  124. def getContactById(self, id):
  125. """Get a `contact` by id
  126.  
  127. :param id: id of a `contact`
  128. """
  129. for contact in self.contacts:
  130. if contact.id == id:
  131. return contact
  132. if self.profile:
  133. if self.profile.id == id:
  134. return self.profile
  135.  
  136. return None
  137.  
  138. def getContactOrRoomOrGroupById(self, id):
  139. """Get a `contact` or `room` or `group` by its id
  140.  
  141. :param id: id of a instance
  142. """
  143. return self.getContactById(id)\
  144. or self.getRoomById(id)\
  145. or self.getGroupById(id)
  146.  
  147. @check_auth
  148. def refreshGroups(self):
  149. """Refresh groups of LineClient"""
  150. self.groups = []
  151.  
  152. self.addGroupsWithIds(self._getGroupIdsJoined())
  153. self.addGroupsWithIds(self._getGroupIdsInvited(), False)
  154.  
  155. @check_auth
  156. def addGroupsWithIds(self, group_ids, is_joined=True):
  157. """Refresh groups of LineClient"""
  158. new_groups = self._getGroups(group_ids)
  159.  
  160. self.groups += [LineGroup(self, group, is_joined) for group in new_groups]
  161.  
  162. self.groups.sort()
  163.  
  164. @check_auth
  165. def refreshContacts(self):
  166. """Refresh contacts of LineClient """
  167. contact_ids = self._getAllContactIds()
  168. contacts = self._getContacts(contact_ids)
  169.  
  170. self.contacts = [LineContact(self, contact) for contact in contacts]
  171.  
  172. self.contacts.sort()
  173.  
  174. @check_auth
  175. def findAndAddContactByUserid(self, userid):
  176. """Find and add a `contact` by userid
  177.  
  178. :param userid: user id
  179. """
  180. try:
  181. contact = self._findAndAddContactsByUserid(userid)
  182. except TalkException as e:
  183. self.raise_error(e.reason)
  184.  
  185. contact = contact.values()[0]
  186.  
  187. for c in self.contacts:
  188. if c.id == contact.mid:
  189. self.raise_error("%s already exists" % contact.displayName)
  190. return
  191.  
  192. c = LineContact(self, contact)
  193. self.contacts.append(c)
  194.  
  195. self.contacts.sort()
  196. return c
  197.  
  198. @check_auth
  199. def _findAndAddContactByPhone(self, phone):
  200. """Find and add a `contact` by phone number
  201.  
  202. :param phone: phone number (unknown format)
  203. """
  204. try:
  205. contact = self._findAndAddContactsByPhone(phone)
  206. except TalkException as e:
  207. self.raise_error(e.reason)
  208.  
  209. contact = contact.values()[0]
  210.  
  211. for c in self.contacts:
  212. if c.id == contact.mid:
  213. self.raise_error("%s already exists" % contact.displayName)
  214. return
  215.  
  216. c = LineContact(self, contact)
  217. self.contacts.append(c)
  218.  
  219. self.contacts.sort()
  220. return c
  221.  
  222. @check_auth
  223. def _findAndAddContactByEmail(self, email):
  224. """Find and add a `contact` by email
  225.  
  226. :param email: email
  227. """
  228. try:
  229. contact = self._findAndAddContactsByEmail(email)
  230. except TalkException as e:
  231. self.raise_error(e.reason)
  232.  
  233. contact = contact.values()[0]
  234.  
  235. for c in self.contacts:
  236. if c.id == contact.mid:
  237. self.raise_error("%s already exists" % contact.displayName)
  238. return
  239.  
  240. c = LineContact(self, contact)
  241. self.contacts.append(c)
  242.  
  243. self.contacts.sort()
  244. return c
  245.  
  246. @check_auth
  247. def _findContactByUserid(self, userid):
  248. """Find a `contact` by userid
  249.  
  250. :param userid: user id
  251. """
  252. try:
  253. contact = self._findContactByUserid(userid)
  254. except TalkException as e:
  255. self.raise_error(e.reason)
  256.  
  257. return LineContact(self, contact)
  258.  
  259. @check_auth
  260. def refreshActiveRooms(self):
  261. """Refresh active chat rooms"""
  262. start = 1
  263. count = 50
  264.  
  265. self.rooms = []
  266.  
  267. while True:
  268. channel = self._getMessageBoxCompactWrapUpList(start, count)
  269.  
  270. for box in channel.messageBoxWrapUpList:
  271. if box.messageBox.midType == ToType.ROOM:
  272. room = LineRoom(self, self._getRoom(box.messageBox.id))
  273. self.rooms.append(room)
  274.  
  275. if len(channel.messageBoxWrapUpList) == count:
  276. start += count
  277. else:
  278. break
  279.  
  280. @check_auth
  281. def createGroupWithIds(self, name, ids=[]):
  282. """Create a group with contact ids
  283.  
  284. :param name: name of group
  285. :param ids: list of contact ids
  286. """
  287. try:
  288. group = LineGroup(self, self._createGroup(name, ids))
  289. self.groups.append(group)
  290.  
  291. return group
  292. except Exception as e:
  293. self.raise_error(e)
  294.  
  295. return None
  296.  
  297. @check_auth
  298. def createGroupWithContacts(self, name, contacts=[]):
  299. """Create a group with contacts
  300.  
  301. :param name: name of group
  302. :param contacts: list of contacts
  303. """
  304. try:
  305. contact_ids = []
  306. for contact in contacts:
  307. contact_ids.append(contact.id)
  308.  
  309. group = LineGroup(self, self._createGroup(name, contact_ids))
  310. self.groups.append(group)
  311.  
  312. return group
  313. except Exception as e:
  314. self.raise_error(e)
  315.  
  316. return None
  317.  
  318. def getGroupByName(self, name):
  319. """Get a group by name
  320.  
  321. :param name: name of a group
  322. """
  323. for group in self.groups:
  324. if name == group.name:
  325. return group
  326.  
  327. return None
  328.  
  329. def getGroupById(self, id):
  330. """Get a group by id
  331.  
  332. :param id: id of a group
  333. """
  334. for group in self.groups:
  335. if group.id == id:
  336. return group
  337.  
  338. return None
  339.  
  340. @check_auth
  341. def inviteIntoGroup(self, group, contacts=[]):
  342. """Invite contacts into group
  343.  
  344. :param group: LineGroup instance
  345. :param contacts: LineContact instances to invite
  346. """
  347. contact_ids = [contact.id for contact in contacts]
  348. self._inviteIntoGroup(group.id, contact_ids)
  349.  
  350. def acceptGroupInvitation(self, group):
  351. """Accept a group invitation
  352.  
  353. :param group: LineGroup instance
  354. """
  355. if self._check_auth():
  356. try:
  357. self._acceptGroupInvitation(group.id)
  358. return True
  359. except Exception as e:
  360. self.raise_error(e)
  361. return False
  362.  
  363. @check_auth
  364. def leaveGroup(self, group):
  365. """Leave a group
  366.  
  367. :param group: LineGroup instance to leave
  368. """
  369. try:
  370. self._leaveGroup(group.id)
  371. self.groups.remove(group)
  372.  
  373. return True
  374. except Exception as e:
  375. self.raise_error(e)
  376.  
  377. return False
  378.  
  379. @check_auth
  380. def createRoomWithIds(self, ids=[]):
  381. """Create a chat room with contact ids"""
  382. try:
  383. room = LineRoom(self, self._createRoom(ids))
  384. self.rooms.append(room)
  385.  
  386. return room
  387. except Exception as e:
  388. self.raise_error(e)
  389.  
  390. return None
  391.  
  392. @check_auth
  393. def createRoomWithContacts(self, contacts=[]):
  394. """Create a chat room with contacts"""
  395. try:
  396. contact_ids = []
  397. for contact in contacts:
  398. contact_ids.append(contact.id)
  399.  
  400. room = LineRoom(self, self._createRoom(contact_ids))
  401. self.rooms.append(room)
  402.  
  403. return room
  404. except Exception as e:
  405. self.raise_error(e)
  406.  
  407. return None
  408.  
  409. def getRoomById(self, id):
  410. """Get a room by id
  411.  
  412. :param id: id of a room
  413. """
  414. for room in self.rooms:
  415. if room.id == id:
  416. return room
  417.  
  418. return None
  419.  
  420. @check_auth
  421. def inviteIntoRoom(self, room, contacts=[]):
  422. """Invite contacts into room
  423.  
  424. :param room: LineRoom instance
  425. :param contacts: LineContact instances to invite
  426. """
  427. contact_ids = [contact.id for contact in contacts]
  428. self._inviteIntoRoom(room.id, contact_ids)
  429.  
  430. @check_auth
  431. def leaveRoom(self, room):
  432. """Leave a room
  433.  
  434. :param room: LineRoom instance to leave
  435. """
  436. try:
  437. self._leaveRoom(room.id)
  438. self.rooms.remove(room)
  439.  
  440. return True
  441. except Exception as e:
  442. self.raise_error(e)
  443.  
  444. return False
  445.  
  446. @check_auth
  447. def sendMessage(self, message, seq=0):
  448. """Send a message
  449.  
  450. :param message: LineMessage instance to send
  451. """
  452. try:
  453. return self._sendMessage(message, seq)
  454. except TalkException as e:
  455. self.updateAuthToken()
  456. try:
  457. return self._sendMessage(message, seq)
  458. except Exception as e:
  459. self.raise_error(e)
  460.  
  461. return False
  462.  
  463. @check_auth
  464. def getMessageBox(self, id):
  465. """Get MessageBox by id
  466.  
  467. :param id: `contact` id or `group` id or `room` id
  468. """
  469. try:
  470. messageBoxWrapUp = self._getMessageBoxCompactWrapUp(id)
  471.  
  472. return messageBoxWrapUp.messageBox
  473. except:
  474. return None
  475.  
  476. @check_auth
  477. def getRecentMessages(self, messageBox, count):
  478. """Get recent message from MessageBox
  479.  
  480. :param messageBox: MessageBox object
  481. """
  482. id = messageBox.id
  483. messages = self._getRecentMessages(id, count)
  484.  
  485. return self.getLineMessageFromMessage(messages)
  486.  
  487. @check_auth
  488. def longPoll(self, count=50, debug=False):
  489. """Receive a list of operations that have to be processed by original
  490. Line cleint.
  491.  
  492. :param count: number of operations to get from
  493. :returns: a generator which returns operations
  494.  
  495. >>> for op in client.longPoll():
  496. sender = op[0]
  497. receiver = op[1]
  498. message = op[2]
  499. print "%s->%s : %s" % (sender, receiver, message)
  500. """
  501. """Check is there any operations from LINE server"""
  502. OT = OperationType
  503.  
  504. try:
  505. operations = self._fetchOperations(self.revision, count)
  506. except EOFError:
  507. return
  508. except TalkException as e:
  509. if e.code == 9:
  510. self.raise_error("user logged in to another machine")
  511. else:
  512. return
  513.  
  514. for operation in operations:
  515. if debug:
  516. print operation
  517. if operation.type == OT.END_OF_OPERATION:
  518. pass
  519. elif operation.type == OT.SEND_MESSAGE:
  520. pass
  521. elif operation.type == OT.RECEIVE_MESSAGE:
  522. message = LineMessage(self, operation.message)
  523.  
  524. raw_sender = operation.message._from
  525. raw_receiver = operation.message.to
  526.  
  527. sender = self.getContactOrRoomOrGroupById(raw_sender)
  528. receiver = self.getContactOrRoomOrGroupById(raw_receiver)
  529.  
  530. # If sender is not found, check member list of group chat sent to
  531. if sender is None:
  532. try:
  533. for m in receiver.members:
  534. if m.id == raw_sender:
  535. sender = m
  536. break
  537. except (AttributeError, TypeError):
  538. pass
  539.  
  540. # If sender is not found, check member list of room chat sent to
  541. if sender is None:
  542. try:
  543. for m in receiver.contacts:
  544. if m.id == raw_sender:
  545. sender = m
  546. break
  547. except (AttributeError, TypeError):
  548. pass
  549.  
  550. if sender is None or receiver is None:
  551. self.refreshGroups()
  552. self.refreshContacts()
  553. self.refreshActiveRooms()
  554.  
  555. sender = self.getContactOrRoomOrGroupById(raw_sender)
  556. receiver = self.getContactOrRoomOrGroupById(raw_receiver)
  557.  
  558. if sender is None or receiver is None:
  559. contacts = self._getContacts([raw_sender, raw_receiver])
  560. if contacts:
  561. if len(contacts) == 2:
  562. sender = LineContact(self, contacts[0])
  563. receiver = LineContact(self, contacts[1])
  564.  
  565. yield (sender, receiver, message)
  566. elif operation.type in [ 60, 61 ]:
  567. pass
  568. else:
  569. print "[*] %s" % OT._VALUES_TO_NAMES[operation.type]
  570. print operation
  571.  
  572. self.revision = max(operation.revision, self.revision)
  573.  
  574. def createContactOrRoomOrGroupByMessage(self, message):
  575. if message.toType == ToType.USER:
  576. pass
  577. elif message.toType == ToType.ROOM:
  578. pass
  579. elif message.toType == ToType.GROUP:
  580. pass
  581.  
  582. def getLineMessageFromMessage(self, messages=[]):
  583. """Change Message objects to LineMessage objects
  584.  
  585. :param messges: list of Message object
  586. """
  587. return [LineMessage(self, message) for message in messages]
  588.  
  589. def _check_auth(self):
  590. """Check if client is logged in or not"""
  591. if self.authToken:
  592. return True
  593. else:
  594. msg = "you need to login"
  595. self.raise_error(msg)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement