/// <summary> /// Mark this conversation as read or unread on the server. /// </summary> private void MarkReadConversation() { if (CIX.Online) { try { string url = string.Format("personalmessage/{0}/{1}/toggleread", RemoteID, UnreadCount > 0); HttpWebRequest request = APIRequest.Get(url, APIRequest.APIFormat.XML); string responseString = APIRequest.ReadResponseString(request); // Any non-exception response should treat the action as having completed. The two // possible outcomes are either the message is marked read or the ID is invalid. // The latter case cannot be re-tried so don't repeat the action. Flags &= ~InboxConversationFlags.MarkRead; lock (CIX.DBLock) { CIX.DB.Update(this); } if (responseString == "Success") { LogFile.WriteLine("Conversation {0} marked as read on server", RemoteID); } } catch (Exception e) { CIX.ReportServerExceptions("InboxConversation.MarkReadConversation", e); } } }
/// <summary> /// Sync the user's mugshot as stored in the database with the server. /// </summary> public void Sync() { if (CIX.Online && Username == CIX.Username) { LogFile.WriteLine("Uploading mugshot for {0} to server", Username); using (Image img = System.Drawing.Image.FromStream(new MemoryStream(Image))) { try { HttpWebRequest request = APIRequest.Post("user/setmugshot", APIRequest.APIFormat.XML, img); string responseString = APIRequest.ReadResponseString(request); if (responseString == "Success") { LogFile.WriteLine("Mugshot successfully uploaded"); Pending = false; CreationTime = DateTime.Now; lock (CIX.DBLock) { CIX.DB.Update(this); } } } catch (Exception e) { CIX.ReportServerExceptions("Mugshot.Sync", e); Pending = true; lock (CIX.DBLock) { CIX.DB.Update(this); } } } } }
/// <summary> /// Post a reply message to the server. The ConversationID field of the message must be set to /// a valid conversation ID for the thread to which the reply is being posted. /// </summary> /// <param name="message">The draft InboxMessage to be posted</param> private void Reply(InboxMessage message) { bool hasError = false; try { PMessageReply reply = new PMessageReply { Body = message.Body.EscapeXml(), ConID = RemoteID }; WebRequest request = APIRequest.Post("personalmessage/reply", APIRequest.APIFormat.XML, reply); Stream objStream = APIRequest.ReadResponse(request); if (objStream != null) { using (TextReader reader = new StreamReader(objStream)) { XmlDocument doc = new XmlDocument { InnerXml = reader.ReadLine() }; if (doc.DocumentElement != null) { string responseString = doc.DocumentElement.InnerText; int messageID; if (int.TryParse(responseString, out messageID)) { message.RemoteID = messageID; lock (CIX.DBLock) { CIX.DB.Update(message); } LogFile.WriteLine("Reply {0} posted to server and updated locally", message.RemoteID); } else { hasError = true; } } } } } catch (Exception e) { CIX.ReportServerExceptions("InboxConversation.Reply", e); hasError = true; } if (hasError) { Flags |= InboxConversationFlags.Error; lock (CIX.DBLock) { CIX.DB.Update(this); } } }
/// <summary> /// Refresh this profile from the server. /// </summary> public void Refresh() { if (CIX.Online) { LogFile.WriteLine("Profile for {0} requested from server", Username); try { // First get the basic profile information string profileUrl = Username == CIX.Username ? "user/profile" : "user/" + Username + "/profile"; HttpWebRequest request = APIRequest.Get(profileUrl, APIRequest.APIFormat.XML); Stream objStream = APIRequest.ReadResponse(request); if (objStream != null) { using (XmlReader reader = XmlReader.Create(objStream)) { XmlSerializer serializer = new XmlSerializer(typeof(ProfileSmall)); ProfileSmall profileSet = (ProfileSmall)serializer.Deserialize(reader); Location = profileSet.Location; FullName = profileSet.Fname + " " + profileSet.Sname; EMailAddress = profileSet.Email; LastOn = DateTime.Parse(profileSet.LastOn); Sex = profileSet.Sex; Flags = (NotificationFlags)profileSet.Flags; lock (CIX.DBLock) { CIX.DB.Update(this); } LogFile.WriteLine("Profile for {0} updated from server", Username); } } request = APIRequest.Get("user/" + Username + "/resume", APIRequest.APIFormat.XML); string resumeText = APIRequest.ReadResponseString(request); if (!string.IsNullOrEmpty(resumeText) && CIX.DB != null) { About = resumeText.UnescapeXml(); lock (CIX.DBLock) { CIX.DB.Update(this); } LogFile.WriteLine("Resume for {0} updated from server", Username); CIX.ProfileCollection.NotifyProfileUpdated(this); } } catch (Exception e) { CIX.ReportServerExceptions("Profile.Refresh", e); } Debug.Flush(); } }
private void Account_Load(object sender, EventArgs e) { CIX.ProfileCollection.ProfileUpdated += OnProfileUpdated; CIX.MugshotUpdated += OnMugshotUpdated; CIX.FolderCollection.AccountUpdated += OnAccountUpdated; CIX.RefreshUserAccount(); RefreshAccount(Profile.ProfileForUser(CIX.Username), true); CIX.ProfileCollection.Get(CIX.Username).Refresh(); }
/// <summary> /// Contains the thread where inbox interactions with the server are contained. Events /// are fired from within the thread to the UI handler to indicate changes. /// </summary> internal void Sync() { try { PostMessages(); Refresh(); } catch (Exception e) { CIX.ReportServerExceptions("ConversationCollection.Sync", e); } }
/// <summary> /// Execution task to retrieve a mugshot for the specified username from the server. /// </summary> public void Refresh() { if (CIX.Online) { LogFile.WriteLine("Mugshot for {0} requested from server", Username); try { HttpWebRequest request = APIRequest.Get("user/" + Username + "/mugshot", APIRequest.APIFormat.XML); HttpWebResponse response = (HttpWebResponse)request.GetResponse(); Stream responseStream = response.GetResponseStream(); if (responseStream != null) { byte[] imageBytes; using (BinaryReader reader = new BinaryReader(responseStream)) { imageBytes = reader.ReadBytes((int)response.ContentLength); } // Crop the user mugshot and scale it down so we're only storing a centered // square of the required dimensions. TypeConverter tc = TypeDescriptor.GetConverter(typeof(Image)); Image mugshotImage = (Image)tc.ConvertFrom(imageBytes); mugshotImage = mugshotImage.ResizeImage(MaxMugshotWidth, MaxMugshotHeight); ImageConverter converter = new ImageConverter(); imageBytes = (byte[])converter.ConvertTo(mugshotImage, typeof(byte[])); Image = imageBytes; CreationTime = DateTime.Now; lock (CIX.DBLock) { CIX.DB.Update(this); } Cache[Username] = this; LogFile.WriteLine("Mugshot for {0} updated from server", Username); CIX.NotifyMugshotUpdated(this); } } catch (Exception e) { CIX.ReportServerExceptions("Mugshot.Refresh", e); } Debug.Flush(); } }
/// <summary> /// Display this view with the specified folder and options /// </summary> public override bool ViewFromFolder(FolderBase folder, Address address, FolderOptions flags) { if (_welcomePage == null) { FillCanvas(); } if (CIX.Online) { CIX.RefreshOnlineUsers(); FolderCollection.RefreshInterestingThreads(); } return(true); }
/// <summary> /// Set the mugshot for the current user. First change in the database and if we /// have network access, change on the server. If there's no network access we /// mark this as needing updating in the configuration. /// </summary> /// <param name="newMugshot">An image specifying the new mugshot</param> public void Update(Image newMugshot) { // Make sure the input image is the maximum size allowed newMugshot = newMugshot.ResizeImage(MaxMugshotWidth, MaxMugshotHeight); ImageConverter converter = new ImageConverter(); Mugshot mugshot = CIX.DB.Table <Mugshot>().SingleOrDefault(c => c.Username == CIX.Username); if (mugshot != null) { mugshot.Image = (byte[])converter.ConvertTo(newMugshot, typeof(byte[])); mugshot.CreationTime = DateTime.Now; lock (CIX.DBLock) { CIX.DB.Update(mugshot); } } else { mugshot = new Mugshot { Username = CIX.Username, CreationTime = DateTime.Now, Image = (byte[])converter.ConvertTo(newMugshot, typeof(byte[])) }; lock (CIX.DBLock) { CIX.DB.Insert(mugshot); } } Cache.Remove(CIX.Username); _realImage = null; if (!CIX.Online) { Pending = true; lock (CIX.DBLock) { CIX.DB.Update(mugshot); } } else { mugshot.Sync(); } CIX.NotifyMugshotUpdated(mugshot); }
/// <summary> /// Synchronise moderators list changes with the server /// </summary> private void SyncModerators() { Thread t = new Thread(() => { try { string encodedForumName = FolderCollection.EncodeForumName(Name); foreach (string part in AddedModerators) { string url = string.Format("moderator/{0}/{1}/modadd", encodedForumName, part); HttpWebRequest getUrl = APIRequest.Get(url, APIRequest.APIFormat.XML); string responseString = APIRequest.ReadResponseString(getUrl); if (responseString == "Success") { LogFile.WriteLine("Moderator {0} successfully added to {1}", part, Name); } } foreach (string part in RemovedModerators) { string url = string.Format("moderator/{0}/{1}/modrem", encodedForumName, part); HttpWebRequest getUrl = APIRequest.Get(url, APIRequest.APIFormat.XML); string responseString = APIRequest.ReadResponseString(getUrl); if (responseString == "Success") { LogFile.WriteLine("Moderator {0} successfully removed from {1}", part, Name); } } // Clear out the current moderators lists to force a refresh from the server AddedMods = string.Empty; RemovedMods = string.Empty; Mods = string.Empty; lock (CIX.DBLock) { CIX.DB.Update(this); } // Notify interested parties that the moderators list has changed CIX.DirectoryCollection.NotifyModeratorsUpdated(this); } catch (Exception e) { CIX.ReportServerExceptions("DirForum.SyncModerators", e); } }); t.Start(); }
/// <summary> /// Handle the Login button and cache the username and password entered. If the /// Remember option was checked, save the username in the global settings. /// </summary> private void fldOK_Click(object sender, EventArgs e) { if (Username != null && fldUsername.Text != Username) { fldError.Visible = true; return; } if (Password != null && fldPassword.Text != Password) { fldError.Visible = true; return; } // Authenticate online if possible // Disabling the buttons is symbolic anyway. Just to show something is happening. fldOK.Enabled = false; fldCancel.Enabled = false; CIX.AuthenticateResponse success = CIX.Authenticate(fldUsername.Text, fldPassword.Text); fldOK.Enabled = true; fldCancel.Enabled = true; if (success == CIX.AuthenticateResponse.Unconnected) { MessageBox.Show(Properties.Resources.NoConnection, Properties.Resources.AppTitle, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (success == CIX.AuthenticateResponse.Inactivated) { fldError.Text = Properties.Resources.InactivatedAccount; fldError.Visible = true; return; } if (success == CIX.AuthenticateResponse.Failure) { fldError.Text = Properties.Resources.BadUsernameOrPassword; fldError.Visible = true; return; } Username = fldUsername.Text; Password = fldPassword.Text; Settings.CurrentUser.SetString("LastUser", Username); DialogResult = DialogResult.OK; Close(); }
/// <summary> /// Post this message to the server /// </summary> private void PostMessage() { CIX.FolderCollection.NotifyMessagePostStarted(this); PostPending = false; try { Folder folder = Topic; PostMessage postMessage = new PostMessage { Body = Body.FixQuotes(), Forum = folder.ParentFolder.Name, Topic = folder.Name, WrapColumn = "0", MarkRead = "1", MsgID = CommentID.ToString(CultureInfo.InvariantCulture) }; HttpWebRequest postUrl = APIRequest.Post("forums/post", APIRequest.APIFormat.XML, postMessage); string responseString = APIRequest.ReadResponseString(postUrl); int newRemoteID; if (int.TryParse(responseString, out newRemoteID)) { RemoteID = newRemoteID; Date = DateTime.UtcNow.UTCToGMTBST(); lock (CIX.DBLock) { CIX.DB.Update(this); } if (CommentID == 0) { LogFile.WriteLine("Posted new thread \"{0}\" as message {1}", Body.FirstLine(), RemoteID); } else { LogFile.WriteLine("Posted new reply to message {0} as message {1}", CommentID, RemoteID); } CIX.FolderCollection.NotifyMessageChanged(this); } else { LogFile.WriteLine("Failed to post message {0} : {1}", ID, responseString); } } catch (Exception e) { CIX.ReportServerExceptions("CIXMessage.PostMessage", e); } CIX.FolderCollection.NotifyMessagePostCompleted(this); }
/// <summary> /// Refresh this topic from the server /// </summary> internal void InternalRefresh() { if (CIX.Online & !_isFolderRefreshing) { _isFolderRefreshing = true; CIX.FolderCollection.NotifyTopicUpdateStarted(this); try { // When refreshing, get the last 30 days worth unless the topic is empty in which // case we get everything. The assumption is that if any changes occur with the // read/unread status on the server then 30 days back is enough to sync those // with the local database. DateTime latestReply = new DateTime(1900, 1, 1); if (Messages.Count > 0) { latestReply = DateTime.Now.Subtract(new TimeSpan(30, 0, 0, 0)); } // First clear the flag so we don't over-refresh RefreshRequired = false; Folder forum = ParentFolder; int countOfNewMessages = 0; string urlFormat = string.Format("forums/{0}/{1}/allmessages", FolderCollection.EncodeForumName(forum.Name), Name); HttpWebRequest request = APIRequest.GetWithQuery(urlFormat, APIRequest.APIFormat.XML, "maxresults=5000&since=" + latestReply.ToString("yyyy-MM-dd HH:mm:ss")); using (Stream objStream = APIRequest.ReadResponse(request)) { if (objStream != null) { countOfNewMessages = FolderCollection.AddMessages(objStream, ref latestReply, false, false); } } if (countOfNewMessages > 0) { LogFile.WriteLine("{0}/{1} refreshed with {2} new messages", forum.Name, Name, countOfNewMessages); } } catch (Exception e) { CIX.ReportServerExceptions("Folder.Refresh", this, e); } CIX.FolderCollection.NotifyTopicUpdateCompleted(this); _isFolderRefreshing = false; } }
/// <summary> /// Do a fixup scan of the messages in the folder and make a request to /// retrieve any missing ones. /// </summary> public void Fixup() { List <Range> listOfRanges = new List <Range>(); int lastMessageID = 0; foreach (CIXMessage message in _allMessages.OrderedMessages) { if (!message.IsPseudo && message.RemoteID != lastMessageID + 1) { Range newRange = new Range { TopicName = Name, ForumName = ParentFolder.Name, Start = lastMessageID + 1, End = message.RemoteID - 1 }; listOfRanges.Add(newRange); } lastMessageID = message.RemoteID; } if (listOfRanges.Count > 0) { Thread t = new Thread(() => { try { HttpWebRequest wrGeturl = APIRequest.Post("forums/messagerange", APIRequest.APIFormat.XML, listOfRanges); Stream objStream = APIRequest.ReadResponse(wrGeturl); if (objStream != null) { DateTime sinceDate = CIX.LastSyncDate; int newMessages = FolderCollection.AddMessages(objStream, ref sinceDate, true, true); if (newMessages > 0) { LogFile.WriteLine("{0}/{1} refreshed with {2} new messages", ParentFolder.Name, Name, newMessages); } } } catch (Exception e) { CIX.ReportServerExceptions("Folder.Fixup", e); } }); t.Start(); } }
/// <summary> /// Sync this profile with the server. /// </summary> public void Sync() { if (CIX.Online && Username == CIX.Username) { string[] splitName = FullName.Split(new[] { ' ' }, 2); LogFile.WriteLine("Uploading profile for {0} to server", CIX.Username); ProfileSet newProfileSmall = new ProfileSet { Fname = splitName[0], Sname = (splitName.Length > 1) ? splitName[1] : string.Empty, Location = Location, Email = EMailAddress, Flags = (int)Flags, Sex = Sex }; try { HttpWebRequest request = APIRequest.Post("user/setprofile", APIRequest.APIFormat.XML, newProfileSmall); string responseString = APIRequest.ReadResponseString(request); if (responseString == "Success") { Pending = false; LogFile.WriteLine("Profile successfully uploaded"); } request = APIRequest.Post("user/setresume", APIRequest.APIFormat.XML, About); responseString = APIRequest.ReadResponseString(request); if (responseString == "True") { Pending = false; LogFile.WriteLine("Resume successfully uploaded"); } } catch (Exception e) { CIX.ReportServerExceptions("Profile.Sync", e); } } }
/// <summary> /// Refresh the list of moderators /// </summary> private void RefreshModerators() { Thread t = new Thread(() => { try { List <string> moderators = new List <string>(); LogFile.WriteLine("Updating list of moderators for {0}", Name); string urlFormat = string.Format("forums/{0}/moderators", FolderCollection.EncodeForumName(Name)); HttpWebRequest wrGeturl = APIRequest.GetWithQuery(urlFormat, APIRequest.APIFormat.XML, "maxresults=10000"); Stream objStream = APIRequest.ReadResponse(wrGeturl); if (objStream != null) { using (XmlReader reader = XmlReader.Create(objStream)) { XmlSerializer serializer = new XmlSerializer(typeof(ForumMods)); ForumMods allModerators = (ForumMods)serializer.Deserialize(reader); moderators.AddRange(allModerators.Mods.Select(mod => mod.Name)); Mods = string.Join(",", moderators); LogFile.WriteLine("List of moderators for {0} updated", Name); lock (CIX.DBLock) { CIX.DB.Update(this); } } } CIX.DirectoryCollection.NotifyModeratorsUpdated(this); } catch (Exception e) { CIX.ReportServerExceptions("DirForum.Moderators", e); } isModeratorsRefreshing = 0; }); t.Start(); }
/// <summary> /// Retrieve an entire conversation. Any new messages are added to the message set and /// an event is fired. /// </summary> /// <param name="root">The root message to which this conversation belongs</param> /// <param name="latestMesssageDate">Ref to a DateTime that is set to the date of the /// most recent message in this conversation</param> /// <returns>The number of messages retrieved</returns> private static int GetConversation(InboxConversation root, ref DateTime latestMesssageDate) { int countOfRead = 0; try { HttpWebRequest request = APIRequest.Get("personalmessage/" + root.RemoteID + "/message", APIRequest.APIFormat.XML); Stream objStream = APIRequest.ReadResponse(request); if (objStream != null) { using (XmlReader reader = XmlReader.Create(objStream)) { XmlSerializer serializer = new XmlSerializer(typeof(PMessageSet)); PMessageSet inboxSet = (PMessageSet)serializer.Deserialize(reader); foreach (CIXInboxMessage message in inboxSet.PMessages) { if (!root.Messages.Contains(message.MessageID)) { InboxMessage newMessage = new InboxMessage { ConversationID = root.ID, RemoteID = message.MessageID, Body = message.Body, Date = DateTime.Parse(message.Date), Author = message.Sender }; root.Messages.AddInternal(newMessage); if (newMessage.Date > latestMesssageDate) { latestMesssageDate = newMessage.Date; } ++countOfRead; } } } } } catch (Exception e) { CIX.ReportServerExceptions("ConversationCollection.GetConversation", e); } return(countOfRead); }
/// <summary> /// Join the specified forum. /// </summary> private void InternalJoin() { try { LogFile.WriteLine("Joining forum {0}", Name); HttpWebRequest request = APIRequest.GetWithQuery("forums/" + FolderCollection.EncodeForumName(Name) + "/join", APIRequest.APIFormat.XML, "mark=true"); string responseString = APIRequest.ReadResponseString(request); if (responseString == "Success") { LogFile.WriteLine("Successfully joined forum {0}", Name); Folder folder = CIX.FolderCollection.Get(-1, Name); if (folder == null) { folder = new Folder { Name = Name, Flags = FolderFlags.Recent, ParentID = -1 }; CIX.FolderCollection.Add(folder); } folder.Flags &= ~FolderFlags.Resigned; lock (CIX.DBLock) { CIX.DB.Update(folder); } CIX.DirectoryCollection.NotifyForumJoined(folder); CIX.FolderCollection.Refresh(false); } JoinPending = false; lock (CIX.DBLock) { CIX.DB.Update(this); } } catch (Exception e) { CIX.ReportServerExceptions("DirForum.Join", e); } }
/// <summary> /// Withdraw this message from the server. /// </summary> private void WithdrawMessage() { try { LogFile.WriteLine("Withdrawing message {0}", RemoteID); Folder topic = Topic; Folder forum = topic.ParentFolder; string urlFormat = string.Format("forums/{0}/{1}/{2}/withdraw", FolderCollection.EncodeForumName(forum.Name), topic.Name, RemoteID); HttpWebRequest request = APIRequest.Get(urlFormat, APIRequest.APIFormat.XML); // Don't try and withdraw again because this was an error. WithdrawPending = false; lock (CIX.DBLock) { CIX.DB.Update(this); } string responseString = APIRequest.ReadResponseString(request); if (responseString == "Success") { LogFile.WriteLine("Successfully withdrawn message {0}", RemoteID); // Replace the message text with the one that we'd get from the server // and save us a round-trip. Body = IsMine ? Resources.WithdrawnByAuthor : Resources.WithdrawnByModerator; lock (CIX.DBLock) { CIX.DB.Update(this); } CIX.FolderCollection.NotifyMessageChanged(this); } else { LogFile.WriteLine("Error withdrawing message. Response is: {1}", forum.Name, responseString); } } catch (Exception e) { CIX.ReportServerExceptions("CIXMessage.WithdrawMessage", e); } }
/// <summary> /// Synchronise the profile collection, updating any changes to the local /// profile and resume that was made offline to the server. /// </summary> public void Sync() { try { Profile selfProfile = Profile.ProfileForUser(CIX.Username); if (selfProfile.Pending) { selfProfile.Sync(); } Mugshot selfMugshot = Mugshot.MugshotForUser(CIX.Username, false); if (selfMugshot.Pending) { selfMugshot.Sync(); } } catch (Exception e) { CIX.ReportServerExceptions("ProfileCollection.Sync", e); } }
/// <summary> /// Request admittance to this forum /// </summary> public void RequestAdmittance() { if (CIX.Online) { Thread t = new Thread(() => { try { StringBuilder textTemplate = new StringBuilder(Resources.AdmissionRequestTemplate1); textTemplate.Replace("$username$", CIX.Username); textTemplate.Replace("$forum$", Name); StringBuilder htmlTemplate = new StringBuilder(Resources.AdmissionRequestTemplate); htmlTemplate.Replace("$username$", CIX.Username); htmlTemplate.Replace("$forum$", Name); SendMail sendMail = new SendMail { Text = textTemplate.ToString(), HTML = htmlTemplate.ToString() }; LogFile.WriteLine("Requesting admission to forum {0}", Name); string url = string.Format("moderator/{0}/sendmessage", Name); HttpWebRequest postUrl = APIRequest.Post(url, APIRequest.APIFormat.XML, sendMail); string responseString = APIRequest.ReadResponseString(postUrl); if (responseString == "Success") { LogFile.WriteLine("Successfully sent admittance request for forum {0}", Name); } } catch (Exception e) { CIX.ReportServerExceptions("DirForum.RequestAdmittance", e); } }); t.Start(); } }
/// <summary> /// Sync forum details with the server. /// </summary> private void SyncDetails() { Thread t = new Thread(() => { try { LogFile.WriteLine("Updating forum {0} to server", Name); Forum newForum = new Forum { Title = Title, Name = Name, Description = Desc, Category = Cat, SubCategory = Sub, Type = Type }; HttpWebRequest postUrl = APIRequest.Post("moderator/forumupdate", APIRequest.APIFormat.XML, newForum); string responseString = APIRequest.ReadResponseString(postUrl); if (responseString == "Success") { LogFile.WriteLine("Forum {0} successfully updated", Name); DetailsPending = false; lock (CIX.DBLock) { CIX.DB.Update(this); } } } catch (Exception e) { CIX.ReportServerExceptions("DirForum.SyncDetails", e); } }); t.Start(); }
/// <summary> /// Delete this conversation from the server. /// </summary> private void DeleteConversation() { if (CIX.Online) { try { // If draft, then just delete if (RemoteID == 0) { CIX.ConversationCollection.Remove(this); return; } HttpWebRequest request = APIRequest.Get("personalmessage/inbox/" + RemoteID + "/rem", APIRequest.APIFormat.XML); string responseString = APIRequest.ReadResponseString(request); if (responseString == "Success") { LogFile.WriteLine("Conversation {0} deleted from inbox", RemoteID); CIX.ConversationCollection.Remove(this); } request = APIRequest.Get("personalmessage/outbox/" + RemoteID + "/rem", APIRequest.APIFormat.XML); responseString = APIRequest.ReadResponseString(request); if (responseString == "Success") { LogFile.WriteLine("Conversation {0} deleted from outbox", RemoteID); CIX.ConversationCollection.Remove(this); } } catch (Exception e) { CIX.ReportServerExceptions("InboxConversation.DeleteConversations", e); } } }
private void SyncProgress_Shown(object sender, System.EventArgs e) { CIX.RefreshStatusEnded += SyncProgress_Completed; CIX.RunAllTasks(); }
/// <summary> /// Resign this folder on the server. /// </summary> private void ResignFolder() { if (!CIX.Online) { ResignPending = true; lock (CIX.DBLock) { CIX.DB.Update(this); } return; } try { string url; if (IsRootFolder) { LogFile.WriteLine("Resigning forum {0}", Name); url = "forums/" + FolderCollection.EncodeForumName(Name) + "/resign"; } else { Folder forum = ParentFolder; LogFile.WriteLine("Resigning topic {0}/{1}", forum.Name, Name); url = "forums/" + FolderCollection.EncodeForumName(forum.Name) + "/" + FolderCollection.EncodeForumName(Name) + "/resigntopic"; } HttpWebRequest request = APIRequest.Get(url, APIRequest.APIFormat.XML); string responseString = APIRequest.ReadResponseString(request); if (responseString == "Success") { LogFile.WriteLine("Successfully resigned from {0}", Name); CIX.FolderCollection.NotifyFolderUpdated(this); } else { LogFile.WriteLine("Error resigning {0}. Response is: {1}", Name, responseString); } if (DeletePending) { DeletePending = false; Delete(false); return; } // Whatever happens, clear the pending action so we don't keep trying to // resign the forum repeatedly. ResignPending = false; Flags |= FolderFlags.Resigned; lock (CIX.DBLock) { CIX.DB.Update(this); } } catch (Exception e) { CIX.ReportServerExceptions("Folder.ResignFolder", this, e); } }
/// <summary> /// Sync this conversation with the server. /// </summary> public void Sync() { if (Flags.HasFlag(InboxConversationFlags.Deleted)) { DeleteConversation(); return; } if (Flags.HasFlag(InboxConversationFlags.MarkRead)) { MarkReadConversation(); } if (Flags.HasFlag(InboxConversationFlags.Error)) { return; } int conversationID = RemoteID; foreach (InboxMessage message in Messages) { if (message.IsDraft) { if (conversationID > 0) { Reply(message); } else { bool hasError = false; try { PMessageAdd newMessage = new PMessageAdd { Body = message.Body.EscapeXml(), Recipient = message.Author, Subject = Subject }; WebRequest request = APIRequest.Post("personalmessage/add", APIRequest.APIFormat.XML, newMessage); Stream objStream = APIRequest.ReadResponse(request); if (objStream != null) { using (TextReader reader = new StreamReader(objStream)) { XmlDocument doc = new XmlDocument { InnerXml = reader.ReadLine() }; if (doc.DocumentElement != null) { string responseString = doc.DocumentElement.InnerText; string[] splitStrings = responseString.Split(','); if (splitStrings.Length == 2) { int messageID; if (int.TryParse(splitStrings[0], out conversationID) && int.TryParse(splitStrings[1], out messageID)) { lock (CIX.DBLock) { RemoteID = conversationID; CIX.DB.Update(this); message.RemoteID = messageID; CIX.DB.Update(message); } LogFile.WriteLine("New message {0} in conversation {1} posted to server and updated locally", message.RemoteID, RemoteID); } } else { hasError = true; } } } } } catch (Exception e) { CIX.ReportServerExceptions("InboxConversation.Sync", e); hasError = true; } // Flag if we hit an error if (hasError) { Flags |= InboxConversationFlags.Error; lock (CIX.DBLock) { CIX.DB.Update(this); } } } } } }
/// <summary> /// Refresh the details of the forum, including title and description. /// </summary> /// <param name="forumName">The forum name</param> public void RefreshForum(string forumName) { Thread t = new Thread(() => { DirForum forum = null; try { string encodedForumName = FolderCollection.EncodeForumName(forumName); LogFile.WriteLine("Updating directory for {0}", forumName); HttpWebRequest wrGeturl = APIRequest.Get("forums/" + encodedForumName + "/details", APIRequest.APIFormat.XML); Stream objStream = APIRequest.ReadResponse(wrGeturl); if (objStream != null) { using (XmlReader reader = XmlReader.Create(objStream)) { XmlSerializer serializer = new XmlSerializer(typeof(ForumDetails)); ForumDetails forumDetails = (ForumDetails)serializer.Deserialize(reader); bool isNewForum = false; forum = ForumByName(forumDetails.Name); if (forum == null) { forum = new DirForum(); isNewForum = true; } forum.Name = forumDetails.Name; forum.Title = forumDetails.Title; forum.Desc = forumDetails.Description; forum.Cat = forumDetails.Category; forum.Sub = forumDetails.SubCategory; forum.Recent = forumDetails.Recent; forum.Type = forumDetails.Type; lock (CIX.DBLock) { if (isNewForum) { CIX.DB.Insert(forum); _allForums[forum.ID] = forum; } else { CIX.DB.Update(forum); } } LogFile.WriteLine("Directory for {0} updated", forum.Name); } } } catch (Exception e) { CIX.ReportServerExceptions("DirectoryCollection.RefreshForum", e); } NotifyForumUpdated(forum); }); t.Start(); }
/// <summary> /// Do database initialisation. /// </summary> /// <returns>True if we initialised successfully, false otherwise</returns> private static bool InitializeDatabase() { string username = LastUser; string databasePath = _databasePath; string password = null; if (databasePath != null) { username = Path.GetFileNameWithoutExtension(databasePath); } else { string docFolder = CIX.HomeFolder; if (!string.IsNullOrEmpty(username)) { databasePath = Path.Combine(docFolder, username + ".cixreader"); if (!File.Exists(databasePath)) { // The lastuser was mysteriously deleted so clear it and start // again by requesting login. username = null; } } if (string.IsNullOrEmpty(username)) { Settings.CurrentUser.SetString("LastUser", string.Empty); Login loginDialog = new Login(); if (loginDialog.ShowDialog() == DialogResult.Cancel) { Application.Exit(); return(false); } username = loginDialog.Username; password = loginDialog.Password; } databasePath = Path.Combine(docFolder, username + ".cixreader"); if (!Directory.Exists(docFolder)) { Directory.CreateDirectory(docFolder); } } // Ensure all tables exist if (!CIX.Init(databasePath)) { MessageBox.Show(@"Cannot open database: " + databasePath); return(false); } // If a cached username was specified and it matches the username we have then we // use that to indicate that the password in the DB is to be used. Otherwise we need // the user to authenticate against the database password. if (CIX.Password == null || CIX.Username == null) { // Prompt for credentials if we don't have them and ensure they match // what is in the database. if (username == null || password == null) { Login loginDialog = new Login { Username = CIX.Username, Password = CIX.Password }; if (loginDialog.ShowDialog() == DialogResult.Cancel) { Application.Exit(); return(false); } username = loginDialog.Username; password = loginDialog.Password; } CIX.Username = username; CIX.Password = password; } string settingsPath = Path.Combine(CIX.HomeFolder, username + ".ini"); Preferences.Open(settingsPath); if (IsFirstRun) { Preferences.StandardPreferences.StartOffline = true; } InitializeLogFile(); LogFile.WriteLine("{0} {1} started", Resources.AppTitle, VersionString); LogFile.WriteLine("Opened database {0}", databasePath); // Compact the database if the time has come int cleanupFrequency = Preferences.StandardPreferences.CacheCleanUpFrequency; if (cleanupFrequency > 0) { DateTime cleanupDate = Preferences.StandardPreferences.LastCacheCleanUp; cleanupDate = cleanupDate.AddDays(cleanupFrequency); if (cleanupDate < DateTime.Now) { CIX.CompactDatabase(); Preferences.StandardPreferences.LastCacheCleanUp = DateTime.Now; } } // Set initial state StartupOnline = (!_forceOffline) && !Preferences.StandardPreferences.StartOffline; StartupAddress = _address ?? Preferences.StandardPreferences.LastAddress; // Use the beta API if the user has opted into beta. APIRequest.UseBetaAPI = Preferences.StandardPreferences.UseBeta; return(true); }
/// <summary> /// Add or remove the star from this message on the server. /// </summary> private void StarMessage() { Folder folder = Topic; if (Starred) { StarAdd addStar = new StarAdd { Forum = Topic.ParentFolder.Name, Topic = folder.Name, MsgID = RemoteID.ToString(CultureInfo.InvariantCulture) }; LogFile.WriteLine("Adding star to message {0} in {1}/{2}", addStar.MsgID, addStar.Forum, addStar.Topic); try { HttpWebRequest postUrl = APIRequest.Post("starred/add", APIRequest.APIFormat.XML, addStar); string responseString = APIRequest.ReadResponseString(postUrl); if (responseString.Contains("Success")) { LogFile.WriteLine("Star successfully added"); } else { LogFile.WriteLine("Failed to add star to message {0} : {1}", RemoteID, responseString); } } catch (Exception e) { CIX.ReportServerExceptions("CIXMessage.StarMessage", e); } StarPending = false; lock (CIX.DBLock) { CIX.DB.Update(this); } } else { string forumName = FolderCollection.EncodeForumName(Topic.ParentFolder.Name); string starUrl = string.Format("starred/{0}/{1}/{2}/rem", forumName, Topic.Name, RemoteID); LogFile.WriteLine("Removing star from message {0} in {1}/{2}", RemoteID, forumName, Topic.Name); try { HttpWebRequest getRequest = APIRequest.Get(starUrl, APIRequest.APIFormat.XML); string responseString = APIRequest.ReadResponseString(getRequest); if (responseString.Contains("Success")) { LogFile.WriteLine("Star successfully removed"); } else { LogFile.WriteLine("Failed to remove star for message {0} : {1}", RemoteID, responseString); } } catch (Exception e) { CIX.ReportServerExceptions("CIXMessage.StarMessage", e); } if (StarPending) { StarPending = false; lock (CIX.DBLock) { CIX.DB.Update(this); } } } }
/// <summary> /// Retrieve new conversations from the server since the last time we checked. /// </summary> public void Refresh() { try { List <CIXInboxItem> inboxItems = new List <CIXInboxItem>(); int totalCountOfRead = 0; HttpWebRequest request = APIRequest.GetWithQuery("personalmessage/inbox", APIRequest.APIFormat.XML, "since=" + _lastCheckDateTime.ToString("yyyy-MM-dd HH:mm:ss")); Stream objStream = APIRequest.ReadResponse(request); if (objStream != null) { using (XmlReader reader = XmlReader.Create(objStream)) { XmlSerializer serializer = new XmlSerializer(typeof(ConversationInboxSet)); ConversationInboxSet inboxSet = (ConversationInboxSet)serializer.Deserialize(reader); foreach (CIXInboxItem conv in inboxSet.Conversations) { inboxItems.Add(conv); InboxConversation root = ConversationByID(conv.ID); if (root == null) { root = new InboxConversation { RemoteID = conv.ID, Date = DateTime.Parse(conv.Date), Subject = conv.Subject, Author = conv.Sender }; Add(root); } } } } request = APIRequest.GetWithQuery("personalmessage/outbox", APIRequest.APIFormat.XML, "since=" + _lastCheckDateTime.ToString("yyyy-MM-dd HH:mm:ss")); objStream = APIRequest.ReadResponse(request); _lastCheckDateTime = DateTime.Now; if (objStream != null) { using (XmlReader reader = XmlReader.Create(objStream)) { XmlSerializer serializer = new XmlSerializer(typeof(ConversationOutboxSet)); ConversationOutboxSet inboxSet = (ConversationOutboxSet)serializer.Deserialize(reader); foreach (CIXOutboxItem conv in inboxSet.Conversations) { // Make a fake CIXInboxItem for each CIXOutboxItem so we can treat // them equally later. inboxItems.Add(new CIXInboxItem { Date = conv.Date, ID = conv.ID, Sender = conv.Recipient, Subject = conv.Subject, Unread = "false" }); InboxConversation root = ConversationByID(conv.ID); if (root == null) { root = new InboxConversation { RemoteID = conv.ID, Date = DateTime.Parse(conv.Date), Subject = conv.Subject, Author = conv.Recipient }; Add(root); } } } } // Defer sending the notification of new root messages until we've got the whole list added // to the database for performance reasons. if (inboxItems.Count > 0) { NotifyConversationAdded(null); } // Once we've got the roots added, check each one for additions to the // conversation. foreach (CIXInboxItem conv in inboxItems) { InboxConversation root = ConversationByID(conv.ID); if (root == null) { continue; } DateTime latestMessageDate = root.Date; int countOfRead = GetConversation(root, ref latestMessageDate); if (countOfRead > 0) { root.UnreadCount = (conv.Unread == "true") ? countOfRead : 0; root.Flags &= ~InboxConversationFlags.MarkRead; root.Date = latestMessageDate; lock (CIX.DBLock) { CIX.DB.Update(root); } } totalCountOfRead += countOfRead; } if (totalCountOfRead > 0) { NotifyConversationChanged(null); LogFile.WriteLine("{0} new private messages retrieved from inbox", totalCountOfRead); } } catch (Exception e) { CIX.ReportServerExceptions("ConversationCollection.Refresh", e); } }