/// <summary> /// Stop and dispose xmpp-related source together with handlers /// </summary> public void StopXmppAndCleanup() { StopXmpp(); // Unsubscribe all handlers for xmpp subscription OnIncomingPrintJobs = null; OnXmppDebugLogging?.Invoke(this, "Clean up event handlers."); OnXmppDebugLogging = null; }
/// <summary> /// Stop and dispose xmpp-related resource /// </summary> private void StopXmpp() { OnXmppDebugLogging?.Invoke(this, "Xmpp Connection - Closing & Cleaning up socket connection with google."); // Cleanup stream & client if (_xmppSslStream != null) { _xmppSslStream.Dispose(); _xmppSslStream = null; } if (_xmppTcpClient != null) { _xmppTcpClient.Dispose(); _xmppTcpClient = null; } }
/// <summary> /// Stop and dispose xmpp-related resource /// </summary> private void StopXmpp() { OnXmppDebugLogging?.Invoke(this, "Xmpp Connection - Closing & Cleaning up socket connection with google."); // Cleanup stream & client if (_xmppSslStream != null) { _xmppSslStream.Dispose(); _xmppSslStream = null; } if (_xmppTcpClient != null) { _xmppTcpClient.Dispose(); _xmppTcpClient = null; } _started = false; OnPrinterStopped?.Invoke(this, new EventArgs()); }
/// <summary> /// Listener loop for subscribing google talk events /// </summary> /// <returns>Returns if the loop is manually break or not</returns> private async Task <bool> ListenForIncomingJobsAsync() { // Async task to listen to google stream for new additions to joblist OnXmppDebugLogging?.Invoke(this, "Xmpp Connection - Listener loop started."); // Only end when _xmppSslStream is cleaned up (set to null) while (_xmppSslStream != null) { try { OnXmppDebugLogging?.Invoke(this, $"Xmpp Connection - Ping at '{DateTime.Now.ToUniversalTime()}'"); OnPing?.Invoke(this, new EventArgs()); // Asnynchronously wait for new xml incoming from google var xmlDoc = await RecieveXmlAsync().ConfigureAwait(false); if (xmlDoc != null && OnIncomingPrintJobs != null) { // If xml node matches 'push:data', it must contain incoming printjob notification from google var pushData = xmlDoc.GetElementsByTagName("push:data"); if (pushData.Count > 0) { // Retrieve printerId & Log var printerIdEncoded = pushData[0].InnerText; var printerId = Encoding.UTF8.GetString(Convert.FromBase64String(printerIdEncoded)); OnXmppDebugLogging?.Invoke(this, $"Xmpp Connection: Recieved job addition event from printer '{printerId}'"); OnIncomingPrintJobs?.Invoke(this, new JobRecievedEventArgs { PrinterId = printerId }); } } } catch (System.Exception ex) { OnXmppDebugLogging?.Invoke(this, $"Xmpp Connection - An Exception was thrown while listening to google, the listener loop is terminated. Exception: '{ex.Message}'"); StopXmpp(); return(false); } } OnXmppDebugLogging?.Invoke(this, "Xmpp Connection - Listener loop ended."); return(true); }
private async Task <XmlDocument> RecieveXmlAsync() { // asynchrnously recieve message from google & parse as xml if possible. var xmlString = await RecieveAsync(); if (xmlString.Length <= 1) { return(null); } var strFormat = xmlString.Contains("<stream:stream") ? "{0}</stream:stream>" : "<stream:stream xmlns:stream=\"http://etherx.jabber.org/streams\">{0}</stream:stream>"; var validXmlString = string.Format(strFormat, xmlString); XmlDocument xmlDoc = new XmlDocument(); try { xmlDoc.LoadXml(validXmlString); } catch (System.Exception ex) { OnXmppDebugLogging?.Invoke(this, $"Xmpp Connection - Failed to parse xml '{validXmlString}' with error '{ex.Message}', instead returning null as recieved XML..."); return(null); } return(xmlDoc); }
public async Task InitXmppAsync(string xmppJid) { await UpdateTokenAsync().ConfigureAwait(false); ConnectConversation = "\n[ConversationBegin]\n"; try { OnXmppDebugLogging?.Invoke(this, "Xmpp Connection - Opening new socket connection with google."); // Setup socket connection _xmppTcpClient = new TcpClient(); await _xmppTcpClient.ConnectAsync(xmppServerHost, xmppServerPort).ConfigureAwait(false); // Setup SSL Wrapper var tcpStream = _xmppTcpClient.GetStream(); _xmppSslStream = new SslStream(tcpStream, false, new RemoteCertificateValidationCallback((s, c, ch, ss) => true), null); // Authenticate await _xmppSslStream.AuthenticateAsClientAsync(xmppServerHost).ConfigureAwait(false); // Begin conversation with google // 1st initial stream request await SendAsync("<stream:stream to=\"gmail.com\" xml:lang=\"en\" version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" xmlns=\"jabber:client\">").ConfigureAwait(false); var streamResp11 = await RecieveAsync().ConfigureAwait(false); var streamResp12 = await RecieveAsync().ConfigureAwait(false); OnXmppDebugLogging?.Invoke(this, "Xmpp Connection - Authenticating with google."); // Authenticate using Oauth2 var authB64 = Convert.ToBase64String(Encoding.UTF8.GetBytes($"\0{xmppJid}\0{_token.AccessToken}")); await SendAsync("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" mechanism=\"X-OAUTH2\" auth:service=\"oauth2\" xmlns:auth=\"http://www.google.com/talk/protocol/auth\">{0}</auth>", authB64).ConfigureAwait(false); var authResp = await RecieveXmlAsync().ConfigureAwait(false); if (authResp == null || authResp.GetElementsByTagName("success").Count < 1) { throw new GoogleCloudPrintException($"Xmpp Connection - Authentication failed, xmpp conversation: '{ConnectConversation}'."); } // 2nd stream request (now authenticated) await SendAsync("<stream:stream to=\"gmail.com\" xml:lang=\"en\" version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" xmlns=\"jabber:client\">").ConfigureAwait(false); var streamResp21 = await RecieveAsync().ConfigureAwait(false); var streamResp22 = await RecieveAsync().ConfigureAwait(false); OnXmppDebugLogging?.Invoke(this, "Xmpp Connection - Subscribing to google cloud print events..."); // Bind Request (to retrieve jid) await SendAsync("<iq type=\"set\" id=\"0\"><bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\"><resource>cloud_print</resource></bind></iq>").ConfigureAwait(false); var bindResp = await RecieveXmlAsync().ConfigureAwait(false); if (bindResp == null) { throw new GoogleCloudPrintException($"Xmpp Connection - Bind failed, xmpp conversation: '{ConnectConversation}'."); } var fullJid = bindResp.GetElementsByTagName("jid")[0].InnerText; var bareJid = fullJid.Substring(0, fullJid.IndexOf('/')); // Establish session await SendAsync("<iq type=\"set\" id=\"2\"><session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/></iq>").ConfigureAwait(false); var sessionResp1 = await RecieveAsync().ConfigureAwait(false); var sessionResp2 = await RecieveAsync().ConfigureAwait(false); // Use jid to now subscribe to google cloud print events await SendAsync("<iq type=\"set\" id=\"3\" to=\"{0}\"><subscribe xmlns=\"google:push\"><item channel=\"cloudprint.google.com\" from=\"cloudprint.google.com\"/></subscribe></iq>", bareJid).ConfigureAwait(false); var subscribeResp = await RecieveAsync().ConfigureAwait(false); OnXmppDebugLogging?.Invoke(this, "Xmpp Connection - Established connection to google and Subscribed to events successfully."); // Finally begin asynchronously listening for events new Task(async() => { // Re-init the handshake if the loop is not manually break if (!await ListenForIncomingJobsAsync().ConfigureAwait(false)) { await InitXmppAsync(xmppJid).ConfigureAwait(false); } }).Start(); OnXmppDebugLogging?.Invoke(this, "Xmpp Connection - Ready."); } catch (GoogleCloudPrintException ex) { StopXmpp(); OnXmppDebugLogging?.Invoke(this, ex.Message); throw ex; } catch (System.Exception ex) { StopXmpp(); var message = $"Xmpp Connection - Exception occured while attempting to establish secure stream with google exception: '{ex.Message}', conversation: '{ConnectConversation}'"; OnXmppDebugLogging?.Invoke(this, message); throw new GoogleCloudPrintException(message); } }