PageRenderTime 51ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/gadu_protocol/socket-notifiers/gadu-protocol-socket-notifiers.cpp

https://gitlab.com/mziab/kadu
C++ | 357 lines | 266 code | 67 blank | 24 comment | 20 complexity | 4e59ba92437cc75aac1399cf3ee37d5b MD5 | raw file
Possible License(s): LGPL-2.1, GPL-3.0, BSD-3-Clause, CC-BY-3.0, GPL-2.0
  1. /*
  2. * %kadu copyright begin%
  3. * Copyright 2011, 2012, 2013 Bartosz Brachaczek (b.brachaczek@gmail.com)
  4. * Copyright 2011, 2012, 2013, 2014, 2015 Rafał Przemysław Malinowski (rafal.przemyslaw.malinowski@gmail.com)
  5. * %kadu copyright end%
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation; either version 2 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include "gadu-protocol-socket-notifiers.h"
  21. #include "services/gadu-imtoken-service.h"
  22. #include "services/gadu-roster-service.h"
  23. #include "services/user-data/gadu-user-data-service.h"
  24. #include "accounts/account.h"
  25. #include "buddies/buddy-set.h"
  26. #include "configuration/configuration.h"
  27. #include "configuration/deprecated-configuration-api.h"
  28. #include "contacts/contact-manager.h"
  29. #include "misc/misc.h"
  30. #include "debug.h"
  31. #include <QtCore/QSocketNotifier>
  32. #include <libgadu.h>
  33. #ifdef Q_OS_WIN
  34. # include <winsock2.h>
  35. #else
  36. # include <arpa/inet.h>
  37. #endif
  38. GaduProtocolSocketNotifiers::GaduProtocolSocketNotifiers(Account account, GaduProtocol *protocol) :
  39. GaduSocketNotifiers{protocol},
  40. m_account{account},
  41. m_protocol{protocol},
  42. m_session{nullptr}
  43. {
  44. }
  45. GaduProtocolSocketNotifiers::~GaduProtocolSocketNotifiers()
  46. {
  47. }
  48. void GaduProtocolSocketNotifiers::setGaduIMTokenService(GaduIMTokenService *imTokenService)
  49. {
  50. m_imTokenService = imTokenService;
  51. }
  52. void GaduProtocolSocketNotifiers::setGaduUserDataService(GaduUserDataService *userDataService)
  53. {
  54. m_userDataService = userDataService;
  55. }
  56. void GaduProtocolSocketNotifiers::watchFor(gg_session *sess)
  57. {
  58. m_session = sess;
  59. GaduSocketNotifiers::watchFor(m_session ? m_session->fd : -1);
  60. if (!m_session)
  61. m_imTokenService->setIMToken({});
  62. }
  63. bool GaduProtocolSocketNotifiers::checkRead()
  64. {
  65. return m_session->check & GG_CHECK_READ;
  66. }
  67. bool GaduProtocolSocketNotifiers::checkWrite()
  68. {
  69. return m_session->check & GG_CHECK_WRITE;
  70. }
  71. void GaduProtocolSocketNotifiers::dumpConnectionState()
  72. {
  73. switch (m_session->state)
  74. {
  75. case GG_STATE_RESOLVING:
  76. kdebugmf(KDEBUG_NETWORK|KDEBUG_INFO, "Resolving address\n");
  77. break;
  78. case GG_STATE_CONNECTING_HUB:
  79. kdebugmf(KDEBUG_NETWORK|KDEBUG_INFO, "Connecting to hub\n");
  80. break;
  81. case GG_STATE_READING_DATA:
  82. kdebugmf(KDEBUG_NETWORK|KDEBUG_INFO, "Fetching data from hub\n");
  83. break;
  84. case GG_STATE_CONNECTING_GG:
  85. kdebugmf(KDEBUG_NETWORK|KDEBUG_INFO, "Connecting to server\n");
  86. break;
  87. case GG_STATE_READING_KEY:
  88. kdebugmf(KDEBUG_NETWORK|KDEBUG_INFO, "Waiting for hash key\n");
  89. break;
  90. case GG_STATE_READING_REPLY:
  91. kdebugmf(KDEBUG_NETWORK|KDEBUG_INFO, "Sending key\n");
  92. break;
  93. case GG_STATE_CONNECTED:
  94. kdebugmf(KDEBUG_NETWORK|KDEBUG_INFO, "connected\n");
  95. break;
  96. case GG_STATE_IDLE:
  97. kdebugmf(KDEBUG_NETWORK|KDEBUG_WARNING, "idle!\n");
  98. break;
  99. case GG_STATE_ERROR:
  100. kdebugmf(KDEBUG_NETWORK|KDEBUG_WARNING, "state==error! error=%d\n", m_session->error);
  101. break;
  102. default:
  103. kdebugmf(KDEBUG_NETWORK|KDEBUG_WARNING, "unknown state! state=%d\n", m_session->state);
  104. break;
  105. }
  106. }
  107. void GaduProtocolSocketNotifiers::handleEventMultilogonInfo(gg_event* e)
  108. {
  109. m_protocol->CurrentMultilogonService->handleEventMultilogonInfo(e);
  110. }
  111. void GaduProtocolSocketNotifiers::handleEventNotify(struct gg_event *e)
  112. {
  113. auto notify = (GG_EVENT_NOTIFY_DESCR == e->type)
  114. ? e->event.notify_descr.notify
  115. : e->event.notify;
  116. while (notify->uin)
  117. {
  118. QString description = (GG_EVENT_NOTIFY_DESCR == e->type)
  119. ? QString::fromUtf8(e->event.notify_descr.descr)
  120. : QString();
  121. m_protocol->socketContactStatusChanged(notify->uin, notify->status, description, 0);
  122. notify++;
  123. }
  124. }
  125. void GaduProtocolSocketNotifiers::handleEventNotify60(struct gg_event *e)
  126. {
  127. auto notify = e->event.notify60;
  128. while (notify->uin)
  129. {
  130. m_protocol->socketContactStatusChanged(notify->uin, notify->status, QString::fromUtf8(notify->descr), notify->image_size);
  131. notify++;
  132. }
  133. }
  134. void GaduProtocolSocketNotifiers::handleEventStatus(struct gg_event *e)
  135. {
  136. if (GG_EVENT_STATUS60 == e->type)
  137. m_protocol->socketContactStatusChanged(e->event.status60.uin, e->event.status60.status, QString::fromUtf8(e->event.status60.descr),
  138. e->event.status60.image_size);
  139. else
  140. m_protocol->socketContactStatusChanged(e->event.status.uin, e->event.status.status, QString::fromUtf8(e->event.status.descr), 0);
  141. }
  142. void GaduProtocolSocketNotifiers::handleEventConnFailed(struct gg_event *e)
  143. {
  144. GaduProtocol::GaduError err;
  145. switch (e->event.failure)
  146. {
  147. case GG_FAILURE_RESOLVING: err = GaduProtocol::ConnectionServerNotFound; break;
  148. case GG_FAILURE_CONNECTING: err = GaduProtocol::ConnectionCannotConnect; break;
  149. case GG_FAILURE_NEED_EMAIL: err = GaduProtocol::ConnectionNeedEmail; break;
  150. case GG_FAILURE_INVALID: err = GaduProtocol::ConnectionInvalidData; break;
  151. case GG_FAILURE_READING: err = GaduProtocol::ConnectionCannotRead; break;
  152. case GG_FAILURE_WRITING: err = GaduProtocol::ConnectionCannotWrite; break;
  153. case GG_FAILURE_PASSWORD: err = GaduProtocol::ConnectionIncorrectPassword; break;
  154. case GG_FAILURE_TLS: err = GaduProtocol::ConnectionTlsError; break;
  155. case GG_FAILURE_INTRUDER: err = GaduProtocol::ConnectionIntruderError; break;
  156. case GG_FAILURE_UNAVAILABLE: err = GaduProtocol::ConnectionUnavailableError; break;
  157. default:
  158. kdebugm(KDEBUG_ERROR, "ERROR: unhandled/unknown connection error! %d\n", e->event.failure);
  159. err = GaduProtocol::ConnectionUnknow;
  160. break;
  161. }
  162. m_protocol->socketConnFailed(err);
  163. // we don't have connection anymore
  164. watchFor(nullptr);
  165. }
  166. void GaduProtocolSocketNotifiers::handleEventConnSuccess(struct gg_event *e)
  167. {
  168. Q_UNUSED(e)
  169. m_protocol->connectedToServer();
  170. }
  171. void GaduProtocolSocketNotifiers::handleEventDisconnect(struct gg_event *e)
  172. {
  173. Q_UNUSED(e)
  174. // close connection
  175. gg_logoff(m_session);
  176. // we don't have connection anymore
  177. watchFor(nullptr);
  178. m_protocol->disconnectedFromServer();
  179. m_protocol->setStatus(Status{}, SourceUser);
  180. }
  181. void GaduProtocolSocketNotifiers::socketEvent()
  182. {
  183. kdebugf();
  184. auto e = gg_watch_fd(m_session);
  185. if (!e || GG_STATE_IDLE == m_session->state)
  186. {
  187. if (e && e->type == GG_EVENT_CONN_FAILED)
  188. handleEventConnFailed(e);
  189. else
  190. m_protocol->socketConnFailed(GaduProtocol::ConnectionUnknow);
  191. return;
  192. }
  193. kdebugmf(KDEBUG_NETWORK|KDEBUG_INFO, "changing QSocketNotifiers.\n");
  194. watchFor(m_session); // maybe fd has changed, we need to check always
  195. dumpConnectionState();
  196. kdebugmf(KDEBUG_NETWORK|KDEBUG_INFO, "event: %d\n", e->type);
  197. switch (e->type)
  198. {
  199. case GG_EVENT_MSG:
  200. emit msgEventReceived(e);
  201. break;
  202. case GG_EVENT_MULTILOGON_MSG:
  203. emit multilogonMsgEventReceived(e);
  204. break;
  205. case GG_EVENT_MULTILOGON_INFO:
  206. handleEventMultilogonInfo(e);
  207. break;
  208. case GG_EVENT_TYPING_NOTIFICATION:
  209. emit typingNotifyEventReceived(e);
  210. break;
  211. case GG_EVENT_NOTIFY:
  212. case GG_EVENT_NOTIFY_DESCR:
  213. handleEventNotify(e);
  214. break;
  215. case GG_EVENT_NOTIFY60:
  216. handleEventNotify60(e);
  217. break;
  218. case GG_EVENT_STATUS:
  219. case GG_EVENT_STATUS60:
  220. handleEventStatus(e);
  221. break;
  222. case GG_EVENT_ACK:
  223. emit ackEventReceived(e);
  224. break;
  225. case GG_EVENT_CONN_FAILED:
  226. handleEventConnFailed(e);
  227. break;
  228. case GG_EVENT_CONN_SUCCESS:
  229. handleEventConnSuccess(e);
  230. break;
  231. case GG_EVENT_DISCONNECT:
  232. handleEventDisconnect(e);
  233. break;
  234. case GG_EVENT_PUBDIR50_SEARCH_REPLY:
  235. m_protocol->CurrentSearchService->handleEventPubdir50SearchReply(e);
  236. // break;
  237. case GG_EVENT_PUBDIR50_READ:
  238. m_protocol->CurrentPersonalInfoService->handleEventPubdir50Read(e);
  239. m_protocol->CurrentContactPersonalInfoService->handleEventPubdir50Read(e);
  240. // break;
  241. case GG_EVENT_PUBDIR50_WRITE:
  242. m_protocol->CurrentPersonalInfoService->handleEventPubdir50Write(e);
  243. break;
  244. case GG_EVENT_IMAGE_REQUEST:
  245. m_protocol->CurrentChatImageService->handleEventImageRequest(e);
  246. break;
  247. case GG_EVENT_IMAGE_REPLY:
  248. m_protocol->CurrentChatImageService->handleEventImageReply(e);
  249. break;
  250. case GG_EVENT_USERLIST100_VERSION:
  251. static_cast<GaduRosterService *>(m_protocol->rosterService())->handleEventUserlist100Version(e);
  252. break;
  253. case GG_EVENT_USERLIST100_REPLY:
  254. static_cast<GaduRosterService *>(m_protocol->rosterService())->handleEventUserlist100Reply(e);
  255. break;
  256. case GG_EVENT_USER_DATA:
  257. m_userDataService->handleUserDataEvent(e->event.user_data);
  258. break;
  259. case GG_EVENT_IMTOKEN:
  260. m_imTokenService->setIMToken(e->event.imtoken.imtoken);
  261. break;
  262. }
  263. gg_free_event(e);
  264. kdebugf2();
  265. }
  266. int GaduProtocolSocketNotifiers::timeout()
  267. {
  268. if (!m_session)
  269. return -1;
  270. auto tout = m_session->timeout;
  271. if (tout < 0)
  272. return tout;
  273. return qMin(tout * 1000, 15000);
  274. }
  275. bool GaduProtocolSocketNotifiers::handleSoftTimeout()
  276. {
  277. kdebugf();
  278. if (!m_session || !m_session->soft_timeout)
  279. return false;
  280. m_session->timeout = 0;
  281. disable();
  282. socketEvent();
  283. enable();
  284. return true;
  285. }
  286. void GaduProtocolSocketNotifiers::connectionTimeout()
  287. {
  288. m_protocol->socketConnFailed(GaduProtocol::ConnectionTimeout);
  289. }
  290. #include "moc_gadu-protocol-socket-notifiers.cpp"