/// <summary> /// Do a ZModem download of the scratchpad and optionally delete the scratchpad /// after a successful completion. /// </summary> /// <param name="buffer">Output buffer</param> private void DownloadCommand(LineBuffer buffer) { buffer.WriteLine("Zmodem download started... (to abort ^X^X^X^X^X)"); buffer.WriteLine(string.Format("Filesize {0} bytes, estimated time at 2880 cps : 1 sec", _scratch.Length)); string scratchFileName = Path.GetTempFileName(); using (FileStream fileStream = new FileStream(scratchFileName, FileMode.Create)) { ASCIIEncoding encoder = new ASCIIEncoding(); byte[] rawScratchpad = encoder.GetBytes(_scratch.ToString()); fileStream.Write(rawScratchpad, 0, rawScratchpad.Length); } ZModem.ZModem zModem = new ZModem.ZModem(buffer.Stream) { Filename = scratchFileName }; bool success = zModem.Send(); buffer.WriteLine(success ? "Download succeeded" : "Download failed"); if (success) { buffer.WriteString("OK to delete the downloaded scratchpad-file? (y/n)? N\b"); string yesNoResponse = buffer.ReadLine(); if (yesNoResponse.Trim() == "Y") { _scratch.Clear(); } } File.Delete(scratchFileName); }
/// <summary> /// Handle a SAY or COMMENT in a forum topic. The current topic must be set before this /// function is called or it does nothing. The replyNumber specifies whether this is a new /// thread (a SAY) or a reply to an existing thread (a COMMENT). A value of 0 starts a new /// thread otherwise it is the number of the message to which this is a reply. /// </summary> /// <param name="buffer">The I/O buffer</param> /// <param name="replyNumber">The message to which this is a reply</param> private void SayOrCommentCommand(LineBuffer buffer, int replyNumber) { if (_currentTopic != null) { PostMessage message = new PostMessage { MsgID = replyNumber, Forum = _currentTopic.Forum.Name, Topic = _currentTopic.Name }; buffer.WriteLine("Enter message. End with '.<CR>'"); // The body of the message comprises multiple lines terminated by a line // that contains a single period character and nothing else. StringBuilder bodyMessage = new StringBuilder(); string bodyLine = buffer.ReadLine(); while (bodyLine != ".") { bodyMessage.AppendLine(bodyLine.Trim()); bodyLine = buffer.ReadLine(); } message.Body = bodyMessage.ToString(); WebRequest wrPosturl = APIRequest.Post("forums/post", APIRequest.APIFormat.XML, message); buffer.WriteString("Adding.."); try { Stream objStream = wrPosturl.GetResponse().GetResponseStream(); if (objStream != null) { using (TextReader reader = new StreamReader(objStream)) { XmlDocument doc = new XmlDocument { InnerXml = reader.ReadLine() }; if (doc.DocumentElement != null) { int newMessageNumber = Int32.Parse(doc.DocumentElement.InnerText); buffer.WriteLine(string.Format("Message {0} added.", newMessageNumber)); } } } } catch (WebException e) { if (e.Message.Contains("401")) { throw new AuthenticationException("Authentication Failed", e); } } } }
/// <summary> /// Handle the top-level Main commands. /// </summary> /// <param name="buffer">The telnet input stream</param> private void TopLevelCommand(LineBuffer buffer) { ChangeState(CoSyState.MAIN); do { if (!buffer.IsRunningScript) { buffer.Output = null; buffer.WriteString(PromptForState()); } }while (!_endThread && !ActionCommand(buffer, buffer.ReadLine())); }
/// <summary> /// Display a prompt and request a Yes or No response. /// </summary> /// <param name="buffer">Line buffer</param> /// <param name="prompt">The prompt string</param> /// <returns>True if the user responded Yes, false if anything else</returns> private static bool Ask(LineBuffer buffer, string prompt) { while (true) { buffer.WriteString(prompt); buffer.WriteString("Y\b"); string yesNo = buffer.ReadLine(); if (string.IsNullOrEmpty(yesNo)) { continue; } if (yesNo.ToUpper().StartsWith("Y")) { return(true); } if (yesNo.ToUpper().StartsWith("N")) { return(false); } } }
/// <summary> /// Handle the BYE command. /// </summary> /// <param name="buffer">Line buffer</param> /// <param name="parser">Parser</param> private bool ByeCommand(LineBuffer buffer, Parser parser) { if (parser.NextArgument() != "y" && _scratch.Length > 0) { buffer.WriteString("OK to delete your scratchpad? (y/n/q)? "); string yesNoQuit = buffer.ReadLine(); if (yesNoQuit == "n") { SaveScratchpad(); } if (yesNoQuit == "q") { return(false); } } return(true); }
/// <summary> /// Handle the RESIGN command. /// </summary> /// <param name="buffer">Input buffer</param> /// <param name="parser">Parser</param> private void ResignCommand(LineBuffer buffer, Parser parser) { string forumName = parser.NextArgument(); string topicName = string.Empty; if (string.IsNullOrEmpty(forumName)) { if (_currentTopic == null) { buffer.WriteString("Conference name? "); forumName = buffer.ReadLine(); } else { forumName = _currentTopic.Forum.Name; } } else { string[] joinParams = forumName.Split(new[] { '/' }); if (joinParams.Length == 2) { forumName = joinParams[0]; topicName = joinParams[1]; } } if (!_forums.IsJoined(forumName)) { buffer.WriteLine(string.Format("You are not a member of conference '{0}'.", forumName)); return; } buffer.WriteLine(string.Format("Resigning from conference '{0}'.", forumName)); _forums.Resign(forumName, topicName); ChangeState(CoSyState.MAIN); }
/// <summary> /// Handle the top-level Main commands. /// </summary> /// <param name="buffer">The telnet input stream</param> private void TopLevelCommand(LineBuffer buffer) { ChangeState(CoSyState.MAIN); do { if (!buffer.IsRunningScript) { buffer.Output = null; buffer.WriteString(PromptForState()); } } while (!_endThread && !ActionCommand(buffer, buffer.ReadLine())); }
/// <summary> /// Handle a SAY or COMMENT in a forum topic. The current topic must be set before this /// function is called or it does nothing. The replyNumber specifies whether this is a new /// thread (a SAY) or a reply to an existing thread (a COMMENT). A value of 0 starts a new /// thread otherwise it is the number of the message to which this is a reply. /// </summary> /// <param name="buffer">The I/O buffer</param> /// <param name="replyNumber">The message to which this is a reply</param> private void SayOrCommentCommand(LineBuffer buffer, int replyNumber) { if (_currentTopic != null) { PostMessage message = new PostMessage { MsgID = replyNumber, Forum = _currentTopic.Forum.Name, Topic = _currentTopic.Name }; buffer.WriteLine("Enter message. End with '.<CR>'"); // The body of the message comprises multiple lines terminated by a line // that contains a single period character and nothing else. StringBuilder bodyMessage = new StringBuilder(); string bodyLine = buffer.ReadLine(); while (bodyLine != ".") { bodyMessage.AppendLine(bodyLine.Trim()); bodyLine = buffer.ReadLine(); } message.Body = bodyMessage.ToString(); StringBuilder postMessageXml = new StringBuilder(); using (XmlWriter writer = XmlWriter.Create(postMessageXml)) { XmlSerializer serializer = new XmlSerializer(typeof (PostMessage)); serializer.Serialize(writer, message); } // Remove the header postMessageXml.Replace("<?xml version=\"1.0\" encoding=\"utf-16\"?>", ""); // Messages are posted as 7-bit ASCII. UTF8Encoding encoder = new UTF8Encoding(); byte[] postMessageBytes = encoder.GetBytes(postMessageXml.ToString()); WebRequest wrPosturl = WebRequest.Create(CIXOAuth.PostUri(CoSyServer.CIXAPIServer + "cix.svc/forums/post.xml")); wrPosturl.Method = "POST"; wrPosturl.ContentLength = encoder.GetByteCount(postMessageXml.ToString()); wrPosturl.ContentType = "application/xml"; Stream dataStream = wrPosturl.GetRequestStream(); dataStream.Write(postMessageBytes, 0, postMessageBytes.Length); dataStream.Close(); buffer.WriteString("Adding.."); try { Stream objStream = wrPosturl.GetResponse().GetResponseStream(); if (objStream != null) { using (TextReader reader = new StreamReader(objStream)) { XmlDocument doc = new XmlDocument {InnerXml = reader.ReadLine()}; if (doc.DocumentElement != null) { int newMessageNumber = Int32.Parse(doc.DocumentElement.InnerText); buffer.WriteLine(string.Format("Message {0} added.", newMessageNumber)); } } } } catch (WebException e) { if (e.Message.Contains("401")) { throw new AuthenticationException("Authentication Failed", e); } } } }
/// <summary> /// Handle the RESIGN command. /// /// CAUTION: The API currently doesn't support resigning topics within a forum, although /// the web service apparently seems to. Until this is supported, the resign command will /// resign entire forums. For safety, if a topic name is specified in the argument we /// bail out and do nothing. /// </summary> /// <param name="buffer">Input buffer</param> /// <param name="parser">Parser</param> private void ResignCommand(LineBuffer buffer, Parser parser) { string forumName = parser.NextArgument(); if (string.IsNullOrEmpty(forumName)) { if (_currentTopic == null) { buffer.WriteString("Conference name? "); forumName = buffer.ReadLine(); } else { forumName = _currentTopic.Forum.Name; } } else { string[] joinParams = forumName.Split(new[] {'/'}); if (joinParams.Length == 2) { return; // Bail out if a topic name was specified. } } if (!_forums.IsJoined(forumName)) { buffer.WriteLine(string.Format("You are not a member of conference '{0}'.", forumName)); return; } buffer.WriteLine(string.Format("Resigning from conference '{0}'.", forumName)); _forums.Resign(forumName); ChangeState(CoSyState.MAIN); }
/// <summary> /// Handle the JOIN command. /// </summary> /// <param name="buffer">Line buffer</param> /// <param name="parser">Parser</param> private void JoinCommand(LineBuffer buffer, Parser parser) { string forumName = parser.NextArgument(); if (!string.IsNullOrEmpty(forumName)) { string topicName = null; string[] joinParams = forumName.Split(new[] {'/'}); if (joinParams.Length == 2) { forumName = joinParams[0]; topicName = joinParams[1]; } if (!_forums.IsJoined(forumName)) { buffer.WriteString(string.Format("You are not registered in '{0}'. ", forumName)); if (Ask(buffer, "Would you like to register (y/n)? ")) { if (!_forums.Join(forumName)) { buffer.WriteRedirectableLine(string.Format("No conference '{0}'.", forumName)); return; } } } Forum thisForum = _forums[forumName]; Topic thisTopic; do { if (topicName != null && !thisForum.Topics.Contains(topicName)) { buffer.WriteLine("Couldn't find topic: No such file or directory"); buffer.WriteLine(string.Format("Topic '{0}' not found.", topicName)); topicName = thisForum.Topics[0].Name; } if (topicName == null) { buffer.WriteString("Topics are:"); for (int c = 0; c < thisForum.Topics.Count; ++c) { string topicString = thisForum.Topics[c].Name; if (c > 0) { buffer.WriteString(","); } buffer.WriteString(string.Format(" '{0}'", topicString)); } buffer.WriteLine(""); buffer.WriteString("Topic? "); topicName = buffer.ReadLine(); if (topicName == "quit") { return; } } thisTopic = thisForum.Topics[topicName]; } while (thisTopic == null); buffer.WriteRedirectableLine(string.Format("Joining conference '{0}', topic '{1}'. {2} new message(s).", forumName, topicName, thisTopic.Unread)); _currentTopic = thisTopic; ChangeState(CoSyState.READ); } }
/// <summary> /// This is the main CoSy client communication thread. /// </summary> /// <param name="client">The handle of the TCP client connection</param> private void HandleClientComm(object client) { TcpClient tcpClient = (TcpClient)client; TelnetStream stream = new TelnetStream(tcpClient.GetStream()); LineBuffer buffer = new LineBuffer(stream); try { DateTime loginTime = DateTime.Now; buffer.WriteLine("CIX Conferencing System"); while (true) { buffer.WriteString("login: "******"qix" || loginString == "cix") { break; } buffer.WriteLine("Unknown login"); } Version ver = Assembly.GetEntryAssembly().GetName().Version; string versionString = string.Format("{0}.{1}.{2}", ver.Major, ver.Minor, ver.Build); buffer.WriteLine(string.Format("{0} {1}", Properties.Resources.CIXAPIProxyTitle, versionString)); buffer.WriteString("Nickname? (Enter 'new' for new user) "); string userName = buffer.ReadLine(); buffer.WriteString("Password: "******""); Console.WriteLine("Logged in as '{0}' with password '{1}'", userName, password); _forums = new Forums(); buffer.WriteLine(string.Format("You are a member of {0} conference(s).", _forums.Count)); buffer.WriteLine("Max scratchsize during file has been set to 20000000 bytes"); TopLevelCommand(buffer); buffer.Output = null; // Round up login time to 1 minute. TimeSpan onlineTime = (DateTime.Now - loginTime).Add(new TimeSpan(0, 1, 0)); buffer.WriteLine(string.Format("{0}, you have been online {1}:{2} on line 5", userName, onlineTime.Hours, onlineTime.Minutes)); buffer.WriteLine("Goodbye from CIX !!!HANGUP NOW!!!"); } catch (IOException) { Console.WriteLine("Client terminated connection"); } catch (IndexOutOfRangeException) { Console.WriteLine("Client terminated connection"); } catch (AuthenticationException) { // Authentication failed. Likely the app has been revoked. Clear // the tokens and force re-authentication. Properties.Settings.Default.oauthToken = ""; Properties.Settings.Default.oauthTokenSecret = ""; Properties.Settings.Default.Save(); } tcpClient.Close(); }
/// <summary> /// Do a ZModem download of the scratchpad and optionally delete the scratchpad /// after a successful completion. /// </summary> /// <param name="buffer">Output buffer</param> private void DownloadCommand(LineBuffer buffer) { buffer.WriteLine("Zmodem download started... (to abort ^X^X^X^X^X)"); buffer.WriteLine(string.Format("Filesize {0} bytes, estimated time at 2880 cps : 1 sec", _scratch.Length)); string scratchFileName = Path.GetTempFileName(); using (FileStream fileStream = new FileStream(scratchFileName, FileMode.Create)) { ASCIIEncoding encoder = new ASCIIEncoding(); byte[] rawScratchpad = encoder.GetBytes(_scratch.ToString()); fileStream.Write(rawScratchpad, 0, rawScratchpad.Length); } ZModem.ZModem zModem = new ZModem.ZModem(buffer.Stream) {Filename = scratchFileName}; bool success = zModem.Send(); buffer.WriteLine(success ? "Download succeeded" : "Download failed"); if (success) { buffer.WriteString("OK to delete the downloaded scratchpad-file? (y/n)? N\b"); string yesNoResponse = buffer.ReadLine(); if (yesNoResponse.Trim() == "Y") { _scratch.Clear(); } } File.Delete(scratchFileName); }
/// <summary> /// Handle the BYE command. /// </summary> /// <param name="buffer">Line buffer</param> /// <param name="parser">Parser</param> private bool ByeCommand(LineBuffer buffer, Parser parser) { if (parser.NextArgument() != "y" && _scratch.Length > 0) { buffer.WriteString("OK to delete your scratchpad? (y/n/q)? "); string yesNoQuit = buffer.ReadLine(); if (yesNoQuit == "q") { return false; } } return true; }
/// <summary> /// Display a prompt and request a Yes or No response. /// </summary> /// <param name="buffer">Line buffer</param> /// <param name="prompt">The prompt string</param> /// <returns>True if the user responded Yes, false if anything else</returns> private static bool Ask(LineBuffer buffer, string prompt) { while (true) { buffer.WriteString(prompt); buffer.WriteString("Y\b"); string yesNo = buffer.ReadLine(); if (string.IsNullOrEmpty(yesNo)) { continue; } if (yesNo.ToUpper().StartsWith("Y")) { return true; } if (yesNo.ToUpper().StartsWith("N")) { return false; } } }
/// <summary> /// This is the main CoSy client communication thread. /// </summary> /// <param name="client">The handle of the TCP client connection</param> private void HandleClientComm(object client) { TcpClient tcpClient = (TcpClient)client; TelnetStream stream = new TelnetStream(tcpClient.GetStream()); LineBuffer buffer = new LineBuffer(stream); try { DateTime loginTime = DateTime.Now; buffer.WriteLine("CIX Conferencing System"); while (true) { buffer.WriteString("login: "******"qix" || loginString == "cix") { break; } buffer.WriteLine("Unknown login"); } Version ver = Assembly.GetEntryAssembly().GetName().Version; string versionString = string.Format("{0}.{1}.{2}", ver.Major, ver.Minor, ver.Build); buffer.WriteLine(string.Format("CIX API Proxy {0}", versionString)); buffer.WriteString("Nickname? (Enter 'new' for new user) "); string userName = buffer.ReadLine(); buffer.WriteString("Password: "******""); Console.WriteLine("Logged in as '{0}' with password '{1}'", userName, password); APIRequest.Username = userName; APIRequest.Password = password; LoadScratchpad(); _forums = new Forums(); buffer.WriteLine(string.Format("You are a member of {0} conference(s).", _forums.Count)); buffer.WriteLine("Max scratchsize during file has been set to 20000000 bytes"); TopLevelCommand(buffer); buffer.Output = null; // Round up login time to 1 minute. TimeSpan onlineTime = (DateTime.Now - loginTime).Add(new TimeSpan(0, 1, 0)); buffer.WriteLine(string.Format("{0}, you have been online {1}:{2} on line 5", userName, onlineTime.Hours, onlineTime.Minutes)); buffer.WriteLine("Goodbye from CIX !!!HANGUP NOW!!!"); } catch (IOException) { Console.WriteLine("Client terminated connection"); } catch (IndexOutOfRangeException) { Console.WriteLine("Client terminated connection"); } catch (AuthenticationException) { Console.WriteLine("Client not authorised"); } tcpClient.Close(); }
/// <summary> /// Handle the JOIN command. /// </summary> /// <param name="buffer">Line buffer</param> /// <param name="parser">Parser</param> private void JoinCommand(LineBuffer buffer, Parser parser) { string forumName = parser.NextArgument(); if (!string.IsNullOrEmpty(forumName)) { string topicName = null; string[] joinParams = forumName.Split(new[] { '/' }); if (joinParams.Length == 2) { forumName = joinParams[0]; topicName = joinParams[1]; } if (!_forums.IsJoined(forumName)) { buffer.WriteString(string.Format("You are not registered in '{0}'. ", forumName)); if (Ask(buffer, "Would you like to register (y/n)? ")) { if (!_forums.Join(forumName)) { buffer.WriteRedirectableLine(string.Format("No conference '{0}'.", forumName)); return; } } } Forum thisForum = _forums[forumName]; Topic thisTopic; do { if (topicName != null && !thisForum.Topics.Contains(topicName)) { buffer.WriteLine("Couldn't find topic: No such file or directory"); buffer.WriteLine(string.Format("Topic '{0}' not found.", topicName)); topicName = thisForum.Topics[0].Name; } if (topicName == null) { buffer.WriteString("Topics are:"); for (int c = 0; c < thisForum.Topics.Count; ++c) { string topicString = thisForum.Topics[c].Name; if (c > 0) { buffer.WriteString(","); } buffer.WriteString(string.Format(" '{0}'", topicString)); } buffer.WriteLine(""); buffer.WriteString("Topic? "); topicName = buffer.ReadLine(); if (topicName == "quit") { return; } } thisTopic = thisForum.Topics[topicName]; } while (thisTopic == null); buffer.WriteRedirectableLine(string.Format("Joining conference '{0}', topic '{1}'. {2} new message(s).", forumName, topicName, thisTopic.Unread)); _currentTopic = thisTopic; ChangeState(CoSyState.READ); } }