PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/module/ASC.Jabber/ASC.Xmpp.Host/JabberService.cs

https://github.com/dc0d/ONLYOFFICE-Server
C# | 476 lines | 415 code | 33 blank | 28 comment | 70 complexity | 551fefd7ad3a5ebf9d0788a2b04e1a98 MD5 | raw file
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception
  1. /*
  2. (c) Copyright Ascensio System SIA 2010-2014
  3. This program is a free software product.
  4. You can redistribute it and/or modify it under the terms
  5. of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
  6. Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
  7. to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
  8. any third-party rights.
  9. This program is distributed WITHOUT ANY WARRANTY; without even the implied warranty
  10. of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
  11. the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
  12. You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
  13. The interactive user interfaces in modified source and object code versions of the Program must
  14. display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
  15. Pursuant to Section 7(b) of the License you must retain the original Product logo when
  16. distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
  17. trademark law for use of our trademarks.
  18. All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
  19. content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
  20. International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
  21. */
  22. using ASC.Core;
  23. using ASC.Core.Common.Notify.Jabber;
  24. using ASC.Core.Notify.Jabber;
  25. using ASC.Xmpp.Core.protocol;
  26. using ASC.Xmpp.Core.protocol.client;
  27. using ASC.Xmpp.Core.protocol.extensions.commands;
  28. using ASC.Xmpp.Server;
  29. using ASC.Xmpp.Server.Gateway;
  30. using ASC.Xmpp.Server.Services.Jabber;
  31. using ASC.Xmpp.Server.Session;
  32. using ASC.Xmpp.Server.Storage;
  33. using ASC.Xmpp.Server.Streams;
  34. using log4net;
  35. using System;
  36. using System.Collections.Generic;
  37. using System.Configuration;
  38. using System.Diagnostics;
  39. using System.Linq;
  40. using System.ServiceModel;
  41. using System.Threading.Tasks;
  42. namespace ASC.Xmpp.Host
  43. {
  44. [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, IncludeExceptionDetailInFaults = true,
  45. InstanceContextMode = InstanceContextMode.Single, AddressFilterMode = AddressFilterMode.Any)]
  46. public class JabberService : IJabberService
  47. {
  48. private readonly static ILog _log = LogManager.GetLogger(typeof(JabberService));
  49. private static string fromTeamlabToOnlyOffice = ConfigurationManager.AppSettings["jabber.from-teamlab-to-onlyoffice"] ?? "true";
  50. private static string fromServerInJid = ConfigurationManager.AppSettings["jabber.from-server-in-jid"] ?? "teamlab.com";
  51. private static string toServerInJid = ConfigurationManager.AppSettings["jabber.to-server-in-jid"] ?? "onlyoffice.com";
  52. private readonly XmppServer _xmppServer;
  53. private readonly ReverseJabberServiceClient _reverseJabberServiceClient;
  54. public JabberService(XmppServer xmppServer)
  55. {
  56. _xmppServer = xmppServer;
  57. _reverseJabberServiceClient = new ReverseJabberServiceClient();
  58. }
  59. public int GetNewMessagesCount(int tenantId, string userName)
  60. {
  61. var count = 0;
  62. try
  63. {
  64. count = _xmppServer.StorageManager.OfflineStorage.GetOfflineMessagesCount(GetJid(userName, tenantId));
  65. }
  66. catch (Exception e)
  67. {
  68. _log.ErrorFormat("Unexpected error, userName = {0}, {1}", userName, e);
  69. }
  70. return count;
  71. }
  72. public string GetUserToken(int tenantId, string userName)
  73. {
  74. string token = null;
  75. try
  76. {
  77. token = _xmppServer.AuthManager.GetUserToken(userName);
  78. }
  79. catch (Exception e)
  80. {
  81. _log.ErrorFormat("Unexpected error, userName = {0}, {1}, {2}, {3}", userName,
  82. e.Message, e.StackTrace, e.InnerException != null ? e.InnerException.Message : string.Empty);
  83. }
  84. return token;
  85. }
  86. public void SendMessage(int tenantId, string from, string to, string text, string subject)
  87. {
  88. try
  89. {
  90. _log.DebugFormat("Send Message: tenantId={0}, from={1}, to={2}, text={3}", tenantId, from, to, text);
  91. if (string.IsNullOrEmpty(text))
  92. {
  93. return;
  94. }
  95. if (from == null)
  96. {
  97. _reverseJabberServiceClient.SendMessage(string.Empty, to.ToLowerInvariant(), text, tenantId, string.Empty);
  98. }
  99. var jidFrom = GetJid(from, tenantId);
  100. var jidTo = to != string.Empty ? GetJid(to, tenantId) : new Jid(jidFrom.Server);
  101. var message = new Message(jidTo, jidFrom, MessageType.chat, text);
  102. var sessions = _xmppServer.SessionManager.GetBareJidSessions(jidTo, GetSessionsType.All);
  103. if (sessions.Count != 0)
  104. {
  105. foreach (var session in sessions)
  106. {
  107. if (session != null && !session.IsSignalRFake)
  108. {
  109. ((IXmppSender)_xmppServer.GetService(typeof(IXmppSender))).SendTo(session, message);
  110. }
  111. }
  112. }
  113. else
  114. {
  115. _xmppServer.StorageManager.OfflineStorage.SaveOfflineMessages(message);
  116. }
  117. var handlers = _xmppServer.HandlerManager.HandlerStorage.GetStanzaHandlers(jidFrom, typeof(Message));
  118. if (handlers.Count > 1)
  119. {
  120. var messageArchiveHandler = handlers[1] as MessageArchiveHandler;
  121. if (messageArchiveHandler != null)
  122. {
  123. messageArchiveHandler.HandleMessage(null, message, null);
  124. }
  125. }
  126. }
  127. catch (Exception e)
  128. {
  129. _log.ErrorFormat("Unexpected error, from = {0}, to = {1}, {2}, {3}, {4}", from, to,
  130. e.Message, e.StackTrace, e.InnerException != null ? e.InnerException.Message : string.Empty);
  131. }
  132. }
  133. public void SendCommand(int tenantId, string from, string to, string command, bool fromTenant)
  134. {
  135. try
  136. {
  137. _log.DebugFormat("Send Command: tenantId={0}, from={1}, to={2}, text={3}", tenantId, from, to, command);
  138. if (string.IsNullOrEmpty(from) || string.IsNullOrEmpty(to) || string.IsNullOrEmpty(command)) return;
  139. var toJid = GetJid(to, tenantId, "TMTalk");
  140. var iq = new IQ(IqType.set, fromTenant ? new Jid(from) : GetJid(from, tenantId/*, "TMTalk"*/), toJid)
  141. {
  142. Query = new Command(command)
  143. };
  144. var session = _xmppServer.SessionManager.GetSession(toJid);
  145. if (session != null)
  146. {
  147. var sender = (IXmppSender)_xmppServer.GetService(typeof(IXmppSender));
  148. sender.SendTo(session, iq);
  149. }
  150. }
  151. catch (Exception e)
  152. {
  153. _log.ErrorFormat("Unexpected error, from = {0}, to = {1}, {2}, {3}, {4}", from, to,
  154. e.Message, e.StackTrace, e.InnerException != null ? e.InnerException.Message : string.Empty);
  155. }
  156. }
  157. public void AddXmppConnection(string connectionId, string userName, byte state, int tenantId)
  158. {
  159. try
  160. {
  161. _log.DebugFormat("Add Xmpp Connection: connectionId={0}, userName={1}, state={2}, tenantId={3}", connectionId, userName, state, tenantId);
  162. var jid = GetJid(userName, tenantId, SignalRHelper.SIGNALR_RESOURCE);
  163. var listener = (SignalRXmppListener)((XmppGateway)_xmppServer.GetService(typeof(IXmppReceiver))).GetXmppListener("SignalR Listener");
  164. if (listener.GetXmppConnection(connectionId) != null)
  165. {
  166. RemoveXmppConnection(connectionId, userName, tenantId);
  167. }
  168. listener.AddXmppConnection(connectionId, _xmppServer);
  169. var xmppStream = ((XmppStreamManager)_xmppServer.GetService(typeof(XmppStreamManager))).GetOrCreateNewStream(connectionId);
  170. xmppStream.Authenticate(userName);
  171. string domain = CoreContext.TenantManager.GetTenant(tenantId).TenantDomain;
  172. if (fromTeamlabToOnlyOffice == "true" && domain.EndsWith(fromServerInJid))
  173. {
  174. int place = domain.LastIndexOf(fromServerInJid);
  175. if (place >= 0)
  176. {
  177. domain = domain.Remove(place, fromServerInJid.Length).Insert(place, toServerInJid);
  178. }
  179. }
  180. xmppStream.Domain = domain;
  181. xmppStream.Connected = true;
  182. xmppStream.BindResource(SignalRHelper.SIGNALR_RESOURCE);
  183. var handler = _xmppServer.HandlerManager.HandlerStorage.GetStreamStartHandlers(jid)[0];
  184. var stream = new Stream
  185. {
  186. To = new Jid(jid.Server),
  187. Namespace = "http://etherx.jabber.org/streams",
  188. Version = "1.6",
  189. Language = string.Empty
  190. };
  191. handler.StreamStartHandle(xmppStream, stream, null);
  192. var session = new XmppSession(jid, xmppStream)
  193. {
  194. RosterRequested = false,
  195. Active = true,
  196. IsSignalRFake = true
  197. };
  198. ((XmppSessionManager)_xmppServer.GetService(typeof(XmppSessionManager))).AddSession(session);
  199. var presence = new Presence(SignalRHelper.GetShowType(state), String.Empty, SignalRHelper.PRIORITY)
  200. {
  201. From = jid,
  202. Type = SignalRHelper.GetPresenceType(state)
  203. };
  204. _xmppServer.SessionManager.SetSessionPresence(session, presence);
  205. var sender = (IXmppSender)_xmppServer.GetService(typeof(IXmppSender));
  206. var sessions = _xmppServer.SessionManager.GetSessions().Where(s => s.Id != session.Id).ToArray();
  207. sender.Broadcast(sessions, session.Presence);
  208. var offlineMessages = _xmppServer.StorageManager.OfflineStorage.GetOfflineMessages(jid);
  209. if (offlineMessages.Count > 0)
  210. {
  211. var users = new List<string>();
  212. for (int i = 0; i < offlineMessages.Count; i++)
  213. {
  214. var from = offlineMessages[i].From;
  215. var name = from.User != null ? from.User.ToLowerInvariant() : string.Empty;
  216. if (!users.Contains(name))
  217. {
  218. users.Add(name);
  219. }
  220. }
  221. _reverseJabberServiceClient.SendOfflineMessages(userName, users, tenantId);
  222. _xmppServer.StorageManager.OfflineStorage.RemoveAllOfflineMessages(jid);
  223. }
  224. }
  225. catch (Exception e)
  226. {
  227. _log.ErrorFormat("Unexpected error, userName = {0}, {1}, {2}, {3}", userName,
  228. e, e.StackTrace, e.InnerException != null ? e.InnerException.Message : string.Empty);
  229. }
  230. }
  231. public bool RemoveXmppConnection(string connectionId, string userName, int tenantId)
  232. {
  233. bool result = false;
  234. try
  235. {
  236. _log.DebugFormat("Remove Xmpp Connection: connectionId={0}, userName={1}, tenantId={2}", connectionId, userName, tenantId);
  237. var jid = GetJid(userName, tenantId, SignalRHelper.SIGNALR_RESOURCE);
  238. var listener = (SignalRXmppListener)((XmppGateway)_xmppServer.GetService(typeof(IXmppReceiver))).GetXmppListener("SignalR Listener");
  239. _xmppServer.SessionManager.CloseSession(jid);
  240. _xmppServer.StreamManager.RemoveStream(connectionId);
  241. listener.CloseXmppConnection(connectionId);
  242. var sender = (IXmppSender)_xmppServer.GetService(typeof(IXmppSender));
  243. Task.Run(() =>
  244. {
  245. sender.Broadcast(_xmppServer.SessionManager.GetSessions(),
  246. new Presence { Priority = SignalRHelper.PRIORITY, From = jid, Type = PresenceType.unavailable });
  247. });
  248. var jidSessions = _xmppServer.SessionManager.GetBareJidSessions(jid).Where(s => s.Presence.Type != PresenceType.unavailable).ToArray();
  249. if (jidSessions.Length == 0)
  250. {
  251. result = true;
  252. }
  253. else
  254. {
  255. Task.Run(() =>
  256. {
  257. var bestSessions = jidSessions.Where(s => !s.IsSignalRFake &&
  258. s.Presence.Type != PresenceType.unavailable).OrderByDescending(s => s.Presence.Priority).ToArray();
  259. if (bestSessions.Length > 0 && bestSessions[0].Presence != null)
  260. {
  261. var bestSession = bestSessions[0];
  262. _reverseJabberServiceClient.SendState(bestSession.Jid.User.ToLowerInvariant(),
  263. SignalRHelper.GetState(bestSession.Presence.Show, bestSession.Presence.Type), tenantId, string.Empty);
  264. }
  265. else
  266. {
  267. _log.ErrorFormat("XMPP session Presence is null, userName = {0}", userName);
  268. }
  269. });
  270. result = false;
  271. }
  272. }
  273. catch (Exception e)
  274. {
  275. _log.ErrorFormat("Unexpected error, userName = {0}, {1}, {2}, {3}", userName,
  276. e, e.StackTrace, e.InnerException != null ? e.InnerException.Message : string.Empty);
  277. }
  278. return result;
  279. }
  280. public void SendState(int tenantId, string userName, byte state)
  281. {
  282. try
  283. {
  284. _log.DebugFormat("Send State: tenantId={0}, userName={1}, state={2}", tenantId, userName, state);
  285. var jid = GetJid(userName, tenantId, SignalRHelper.SIGNALR_RESOURCE);
  286. var userSession = _xmppServer.SessionManager.GetSession(jid);
  287. if (userSession != null)
  288. {
  289. var sessions = _xmppServer.SessionManager.GetSessions().Where(s => s.Id != userSession.Id).ToArray();
  290. var sender = (IXmppSender)_xmppServer.GetService(typeof(IXmppSender));
  291. var presence = GetNewPresence(state, null, jid);
  292. _xmppServer.SessionManager.SetSessionPresence(userSession, presence);
  293. sender.Broadcast(sessions, presence);
  294. }
  295. }
  296. catch (Exception e)
  297. {
  298. _log.ErrorFormat("Unexpected error, userName = {0}, {1}, {2}, {3}", userName,
  299. e, e.StackTrace, e.InnerException != null ? e.InnerException.Message : string.Empty);
  300. }
  301. }
  302. public MessageClass[] GetRecentMessages(int tenantId, string from, string to, int id)
  303. {
  304. MessageClass[] messageClasses = null;
  305. try
  306. {
  307. _log.DebugFormat("Get Recent Messages: tenantId={0}, from={1}, to={2}, id={3}", tenantId, from, to, id);
  308. var jidFrom = GetJid(from, tenantId);
  309. var jidTo = GetJid(to, tenantId);
  310. var archiveStore = ((StorageManager)_xmppServer.GetService(typeof(StorageManager))).GetStorage<DbMessageArchive>("archive");
  311. var handlers = _xmppServer.HandlerManager.HandlerStorage.GetStanzaHandlers(jidFrom, typeof(Message));
  312. if (handlers.Count > 1)
  313. {
  314. var messageArchiveHandler = handlers[1] as MessageArchiveHandler;
  315. if (messageArchiveHandler != null)
  316. {
  317. messageArchiveHandler.FlushMessageBuffer();
  318. }
  319. }
  320. var messages = archiveStore.GetMessages(jidFrom, jidTo, id, SignalRHelper.NUMBER_OF_RECENT_MSGS);
  321. messageClasses = new MessageClass[messages.Length];
  322. for (int i = 0; i < messages.Length; i++)
  323. {
  324. messageClasses[i] = new MessageClass();
  325. messageClasses[i].DateTime = messages[i].XDelay != null ? messages[i].XDelay.Stamp : messages[i].DbStamp;
  326. messageClasses[i].Id = messages[i].InternalId;
  327. messageClasses[i].Text = messages[i].Body;
  328. messageClasses[i].UserName = messages[i].From.User;
  329. }
  330. }
  331. catch (Exception e)
  332. {
  333. _log.ErrorFormat("Unexpected error, from = {0}, to = {1}, {2}, {3}:{4}, {5}, {6}", from, to,
  334. e, e.StackTrace, new StackTrace(e, true).GetFrame(0).GetFileLineNumber(),
  335. e.InnerException != null ? e.InnerException.Message : string.Empty, e.ToString());
  336. }
  337. return messageClasses;
  338. }
  339. public Dictionary<string, Dictionary<string, byte>> GetAllStates()
  340. {
  341. var states = new Dictionary<string, Dictionary<string, byte>>();
  342. try
  343. {
  344. _log.Debug("Get All States");
  345. var sessions = _xmppServer.SessionManager.GetSessions().ToArray();
  346. var jids = new List<string>();
  347. for (int i = 0; i < sessions.Length; i++)
  348. {
  349. if(!jids.Contains(sessions[i].Jid.Bare))
  350. {
  351. jids.Add(sessions[i].Jid.Bare);
  352. }
  353. }
  354. for (int i = 0; i < jids.Count; i++)
  355. {
  356. var jidSessions = _xmppServer.SessionManager.GetBareJidSessions(jids[i]).
  357. Where(s => !s.IsSignalRFake).OrderByDescending(s => s.Presence.Priority).ToArray();
  358. if (jidSessions.Length > 0 && jidSessions[0].Presence != null)
  359. {
  360. // for migration from teamlab.com to onlyoffice.com
  361. var domain = jidSessions[0].Jid.Server;
  362. if (fromTeamlabToOnlyOffice == "true" && domain.EndsWith(fromServerInJid))
  363. {
  364. int place = domain.LastIndexOf(fromServerInJid);
  365. if (place >= 0)
  366. {
  367. domain = domain.Remove(place, fromServerInJid.Length).Insert(place, toServerInJid);
  368. }
  369. }
  370. Dictionary<string, byte> tenantStates;
  371. if (!states.TryGetValue(domain, out tenantStates))
  372. {
  373. tenantStates = new Dictionary<string, byte>();
  374. states[domain] = tenantStates;
  375. }
  376. var state = SignalRHelper.GetState(jidSessions[0].Presence.Show, jidSessions[0].Presence.Type);
  377. if (state != SignalRHelper.USER_OFFLINE)
  378. {
  379. tenantStates[jidSessions[0].Jid.User] = state;
  380. }
  381. }
  382. }
  383. }
  384. catch (Exception e)
  385. {
  386. _log.ErrorFormat("Unexpected error {0}", e);
  387. }
  388. return states;
  389. }
  390. public void Ping(string connectionId, int tenantId, string userName, byte state)
  391. {
  392. try
  393. {
  394. _log.DebugFormat("Ping, connectionId={0}, tenantId={1}, userName={2}, state={3}", connectionId, tenantId, userName, state);
  395. var listener = (SignalRXmppListener)((XmppGateway)_xmppServer.GetService(typeof(IXmppReceiver))).GetXmppListener("SignalR Listener");
  396. var connection = listener.GetXmppConnection(connectionId) as SignalRXmppConnection;
  397. if (connection != null)
  398. {
  399. connection.UpdateTimeout();
  400. }
  401. else
  402. {
  403. AddXmppConnection(connectionId, userName, state, tenantId);
  404. }
  405. }
  406. catch (Exception e)
  407. {
  408. _log.ErrorFormat("Unexpected error {0}", e);
  409. }
  410. }
  411. private Presence GetNewPresence(byte state, Presence presence = null, Jid jid = null)
  412. {
  413. if (presence == null)
  414. {
  415. presence = new Presence(SignalRHelper.GetShowType(state), String.Empty) { From = jid, Priority = SignalRHelper.PRIORITY };
  416. }
  417. presence.Show = SignalRHelper.GetShowType(state);
  418. presence.Type = SignalRHelper.GetPresenceType(state);
  419. return presence;
  420. }
  421. private Jid GetJid(string userName, int tenant, string resource = null)
  422. {
  423. var t = CoreContext.TenantManager.GetTenant(tenant);
  424. if (t == null)
  425. {
  426. throw new Exception(string.Format("Tenant with id = {0} not found.", tenant));
  427. }
  428. string domain = t.TenantDomain;
  429. int place = domain.LastIndexOf(toServerInJid);
  430. if (place >= 0)
  431. {
  432. domain = domain.Remove(place, toServerInJid.Length).Insert(place, fromServerInJid);
  433. }
  434. return new Jid(userName, domain, resource);
  435. }
  436. }
  437. }