├── source ├── SkypeQuoteCreator │ ├── Icon.ico │ ├── App.config │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Program.cs │ ├── Analytics.cs │ ├── Settings.cs │ ├── SkypeQuoteCreator.csproj │ ├── MainForm.resx │ ├── MainForm.Designer.cs │ └── MainForm.cs └── OverrideAssemblyVersion.targets ├── .gitignore ├── .gitattributes ├── SkypeQuoteCreator.sln ├── license.txt └── readme.md /source/SkypeQuoteCreator/Icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MatthewKing/SkypeQuoteCreator/HEAD/source/SkypeQuoteCreator/Icon.ico -------------------------------------------------------------------------------- /source/SkypeQuoteCreator/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # build folders 2 | [Bb]in/ 3 | [Oo]bj/ 4 | 5 | # build results 6 | [Dd]ebug/ 7 | [Rr]elease/ 8 | publish/ 9 | 10 | # user-specific files 11 | *.suo 12 | *.user 13 | *.sln.docstates 14 | 15 | # ncrunch 16 | *.crunchsolution* 17 | *.ncrunchsolution* 18 | *.ncrunchproject* 19 | 20 | # nuget 21 | packages/ 22 | 23 | # other 24 | *.[Cc]ache -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /source/SkypeQuoteCreator/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | [assembly: System.Reflection.AssemblyTitle("Skype Quote Creator")] 2 | [assembly: System.Reflection.AssemblyCompany("Matthew King")] 3 | [assembly: System.Reflection.AssemblyProduct("SkypeQuoteCreator")] 4 | [assembly: System.Reflection.AssemblyCopyright("Copyright © Matthew King 2013-2016")] 5 | 6 | [assembly: System.Runtime.InteropServices.ComVisible(false)] 7 | [assembly: System.Runtime.InteropServices.Guid("3390defc-1f8d-4166-8e29-2aa1b29d1e06")] 8 | 9 | [assembly: System.Reflection.AssemblyVersion("1.0.0.0")] 10 | [assembly: System.Reflection.AssemblyFileVersion("1.0.0.0")] 11 | -------------------------------------------------------------------------------- /SkypeQuoteCreator.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SkypeQuoteCreator", "source\SkypeQuoteCreator\SkypeQuoteCreator.csproj", "{2596E3FD-D4B5-4E83-8DC8-8C25855FCD3E}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {2596E3FD-D4B5-4E83-8DC8-8C25855FCD3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {2596E3FD-D4B5-4E83-8DC8-8C25855FCD3E}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {2596E3FD-D4B5-4E83-8DC8-8C25855FCD3E}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {2596E3FD-D4B5-4E83-8DC8-8C25855FCD3E}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /source/SkypeQuoteCreator/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Windows.Forms; 4 | 5 | namespace SkypeQuoteCreator 6 | { 7 | /// 8 | /// Contains the main entry point for the application. 9 | /// 10 | internal static class Program 11 | { 12 | /// 13 | /// The main entry point for the application. 14 | /// 15 | [STAThread] 16 | public static void Main() 17 | { 18 | try 19 | { 20 | if (!Directory.Exists(Settings.DefaultDirectory)) 21 | { 22 | Directory.CreateDirectory(Settings.DefaultDirectory); 23 | } 24 | } 25 | catch 26 | { 27 | // Swallow all exceptions. 28 | } 29 | 30 | Application.EnableVisualStyles(); 31 | Application.SetCompatibleTextRenderingDefault(false); 32 | Application.Run(new MainForm()); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013-2016 Matthew King 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /source/SkypeQuoteCreator/Analytics.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Text; 4 | using System.Windows.Forms; 5 | 6 | namespace SkypeQuoteCreator 7 | { 8 | /// 9 | /// Simple wrapper for keen.io Analytics. 10 | /// 11 | internal static class Analytics 12 | { 13 | private const string Resource = "https://api.keen.io/3.0/projects/{project_id}/events/{event_collection}?api_key={write_key}"; 14 | private const string ProjectId = "53beb382709a39164a00000d"; 15 | private const string WriteKey = "64e2b8a218379d6cfe838fc6999248a2406e68b17afa964a81559d3e63f8cd6e62867ea9c162a5144d477c3ffb2f9e731236fcc128f6e05f214cde257c1bfca2d37f2b6fc81dcfdb360e60cf8a22edea520e73afd7dfa4d32bffa4fc18f61ac4b46da363fd89ab15216839d95d7f4036"; 16 | private const string PayloadFormat = "{'keen':{'addons':[{'name':'keen:ip_to_geo','input':{'ip':'ip_address'},'output':'ip_geo_info'}]},'ip_address':'${keen.ip}','app_name':'{app_name}','app_version':'{app_version}','user_id':'{user_id}','view_name':'{view_name}'}"; 17 | 18 | /// 19 | /// Tracks the screen view. 20 | /// 21 | /// View name. 22 | /// Client ID. 23 | public static void TrackScreenView(string viewName, string clientId) 24 | { 25 | StringBuilder address = new StringBuilder(Resource); 26 | address.Replace("{project_id}", ProjectId); 27 | address.Replace("{event_collection}", "appviews"); 28 | address.Replace("{write_key}", WriteKey); 29 | 30 | StringBuilder data = new StringBuilder(PayloadFormat); 31 | data.Replace("{app_name}", Application.ProductName); 32 | data.Replace("{app_version}", Application.ProductVersion); 33 | data.Replace("{user_id}", clientId); 34 | data.Replace("{view_name}", viewName); 35 | data.Replace("'", "\""); 36 | 37 | using (WebClient client = new WebClient()) 38 | { 39 | client.Headers["Content-Type"] = "application/json"; 40 | 41 | try 42 | { 43 | client.UploadStringAsync( 44 | address: new Uri(address.ToString()), 45 | method: "POST", 46 | data: data.ToString()); 47 | } 48 | catch 49 | { 50 | // Swallow all exceptions. 51 | } 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | Skype Quote Creator 2 | =================== 3 | 4 | A simple WinForms app that allows the user to create a new quote in Skype's clipboard format. 5 | 6 | Deprecation notice 7 | ------------------ 8 | 9 | Please note that this app is no longer actively maintained, and won't work with newer versions of Skype. Skype changed their quote system years ago, and this app does not support their new quote system. I'm no longer an active Skype user so I don't know the details of how the new quote system works. I'd be happy to accept a pull request from any community members who managed to work it out, though. 10 | 11 | Get the application 12 | ------------------- 13 | 14 | You can download the application from the following sources: 15 | 16 | | Application | Description | 17 | |-----------------------------------------------------------------------------|--------------------------------------------| 18 | | [Recommended](https://mking.s3.amazonaws.com/SkypeQuoteCreator.application) | ClickOnce installer with automatic updates | 19 | | [Stand-alone](https://mking.s3.amazonaws.com/SkypeQuoteCreator.exe) | Stand-alone executable | 20 | 21 | Skype clipboard format 22 | ---------------------- 23 | 24 | When a Skype quote is copied to the clipboard, the data object looks something like this: 25 | 26 | | Format | Description | 27 | |----------------------|-----------------------------------------------------------------| 28 | | System.String | Plain-text message | 29 | | Text | Plain-text message | 30 | | UnicodeText | Plain-text message | 31 | | OEMText | Plain-text message | 32 | | SkypeMessageFragment | MemoryStream containing UTF8 Skype message fragment (see below) | 33 | | Locale | MemoryStream containing Cultural identifier (LCID) | 34 | 35 | SkypeMessageFragment 36 | ------------------ 37 | 38 | A simple XML string in the following format: `MessageText`, where `AuthorName` is the Skype user name of the message author, `MessageText` is the message text itself, and `Timestamp` is the number of seconds since the Unix epoch. The actual fragment from Skype contains a few more attributes, but they can be ignored for the purposes of this simple app! 39 | 40 | Copyright 41 | --------- 42 | Copyright 2013-2016 Matthew King. 43 | 44 | License 45 | ------- 46 | Skype Quote Creator is licensed under the [MIT License](http://opensource.org/licenses/MIT). Refer to license.txt for more information. 47 | -------------------------------------------------------------------------------- /source/SkypeQuoteCreator/Settings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Xml.Linq; 6 | 7 | namespace SkypeQuoteCreator 8 | { 9 | /// 10 | /// Represents the application settings file. 11 | /// 12 | internal sealed class Settings 13 | { 14 | /// 15 | /// Gets the default directory for the settings file. 16 | /// 17 | public static string DefaultDirectory { get; } = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "SkypeQuoteCreator"); 18 | 19 | /// 20 | /// Gets the default settings file. 21 | /// 22 | public static Settings Default { get; } = new Settings(Path.Combine(DefaultDirectory, "settings.xml")); 23 | 24 | /// 25 | /// Gets or sets the user ID. 26 | /// 27 | public string UserId { get; set; } 28 | 29 | /// 30 | /// Gets a set containing the names that have been used. 31 | /// 32 | public ISet NameHistory { get; } = new HashSet(StringComparer.OrdinalIgnoreCase); 33 | 34 | /// 35 | /// Settings file path. 36 | /// 37 | private readonly string _path; 38 | 39 | /// 40 | /// Initializes a new instance of the Settings class. 41 | /// 42 | /// Settings file path. 43 | private Settings(string path) 44 | { 45 | _path = path; 46 | } 47 | 48 | /// 49 | /// Saves the settings to the settings file. 50 | /// 51 | public void Save() 52 | { 53 | try 54 | { 55 | string xml = new XDocument(new XElement("Settings", 56 | new XElement("UserId", UserId), 57 | new XElement("NameHistory", NameHistory.Select(name => new XElement("Name", name)).ToArray()))) 58 | .ToString(SaveOptions.None); 59 | 60 | File.WriteAllText(_path, xml); 61 | } 62 | catch 63 | { 64 | // Swallow all exceptions. 65 | } 66 | } 67 | 68 | /// 69 | /// Populates the settings from the settings file. 70 | /// 71 | public void Load() 72 | { 73 | try 74 | { 75 | string xml = File.ReadAllText(_path); 76 | XDocument document = XDocument.Parse(xml); 77 | 78 | UserId = document.Root.Element("UserId")?.Value; 79 | foreach (string name in document.Root.Element("NameHistory").Elements("Name").Select(element => element.Value)) 80 | { 81 | NameHistory.Add(name); 82 | } 83 | } 84 | catch 85 | { 86 | // Swallow all exceptions. 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /source/SkypeQuoteCreator/SkypeQuoteCreator.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {2596E3FD-D4B5-4E83-8DC8-8C25855FCD3E} 8 | WinExe 9 | Properties 10 | SkypeQuoteCreator 11 | SkypeQuoteCreator 12 | v4.0 13 | 512 14 | Client 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | Icon.ico 37 | 38 | 39 | true 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | Form 57 | 58 | 59 | MainForm.cs 60 | 61 | 62 | 63 | 64 | 65 | MainForm.cs 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /source/OverrideAssemblyVersion.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 9 | 10 | 11 | 12 | $(IntermediateOutputPath)\AssemblyInfo.override$(DefaultLanguageSourceExtension) 13 | Properties\AssemblyInfo$(DefaultLanguageSourceExtension) 14 | [assembly: 15 | ] 16 | 17 | 18 | My Project\AssemblyInfo$(DefaultLanguageSourceExtension) 19 | <Assembly: 20 | > 21 | 22 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | <_AssemblyInfoLines_Pass1 Include="@(AssemblyInfoLines)" Condition="'$(AssemblyVersion)'=='' or '$([System.Text.RegularExpressions.Regex]::IsMatch("%(Identity)","(?i)AssemblyVersion"))' == false" /> 32 | <_AssemblyInfoLines_Pass2 Include="@(_AssemblyInfoLines_Pass1)" Condition="'$(AssemblyFileVersion)'=='' or '$([System.Text.RegularExpressions.Regex]::IsMatch("%(Identity)","(?i)AssemblyFileVersion"))' == false" /> 33 | <_AssemblyInfoLines_Pass3 Include="@(_AssemblyInfoLines_Pass2)" Condition="'$(AssemblyInformationalVersion)'=='' or '$([System.Text.RegularExpressions.Regex]::IsMatch("%(Identity)","(?i)AssemblyInformationalVersion"))' == false" /> 34 | 35 | 36 | 37 | 38 | 39 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /source/SkypeQuoteCreator/MainForm.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /source/SkypeQuoteCreator/MainForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace SkypeQuoteCreator 2 | { 3 | partial class MainForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.uxNameLabel = new System.Windows.Forms.Label(); 32 | this.uxMessageLabel = new System.Windows.Forms.Label(); 33 | this.uxMessage = new System.Windows.Forms.TextBox(); 34 | this.uxTimestamp = new System.Windows.Forms.MaskedTextBox(); 35 | this.uxTimestampLabel = new System.Windows.Forms.Label(); 36 | this.uxCopyToClipboard = new System.Windows.Forms.Button(); 37 | this.uxUseCurrentDate = new System.Windows.Forms.Button(); 38 | this.uxName = new System.Windows.Forms.ComboBox(); 39 | this.uxUpdate = new System.Windows.Forms.LinkLabel(); 40 | this.SuspendLayout(); 41 | // 42 | // uxNameLabel 43 | // 44 | this.uxNameLabel.AutoSize = true; 45 | this.uxNameLabel.Location = new System.Drawing.Point(12, 15); 46 | this.uxNameLabel.Name = "uxNameLabel"; 47 | this.uxNameLabel.Size = new System.Drawing.Size(38, 13); 48 | this.uxNameLabel.TabIndex = 5; 49 | this.uxNameLabel.Text = "Name:"; 50 | // 51 | // uxMessageLabel 52 | // 53 | this.uxMessageLabel.AutoSize = true; 54 | this.uxMessageLabel.Location = new System.Drawing.Point(12, 70); 55 | this.uxMessageLabel.Name = "uxMessageLabel"; 56 | this.uxMessageLabel.Size = new System.Drawing.Size(53, 13); 57 | this.uxMessageLabel.TabIndex = 7; 58 | this.uxMessageLabel.Text = "Message:"; 59 | // 60 | // uxMessage 61 | // 62 | this.uxMessage.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 63 | | System.Windows.Forms.AnchorStyles.Left) 64 | | System.Windows.Forms.AnchorStyles.Right))); 65 | this.uxMessage.Location = new System.Drawing.Point(79, 67); 66 | this.uxMessage.Multiline = true; 67 | this.uxMessage.Name = "uxMessage"; 68 | this.uxMessage.Size = new System.Drawing.Size(293, 57); 69 | this.uxMessage.TabIndex = 3; 70 | // 71 | // uxTimestamp 72 | // 73 | this.uxTimestamp.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 74 | | System.Windows.Forms.AnchorStyles.Right))); 75 | this.uxTimestamp.Location = new System.Drawing.Point(79, 40); 76 | this.uxTimestamp.Mask = "0000-00-00 00:00:00"; 77 | this.uxTimestamp.Name = "uxTimestamp"; 78 | this.uxTimestamp.Size = new System.Drawing.Size(196, 20); 79 | this.uxTimestamp.TabIndex = 1; 80 | // 81 | // uxTimestampLabel 82 | // 83 | this.uxTimestampLabel.AutoSize = true; 84 | this.uxTimestampLabel.Location = new System.Drawing.Point(12, 43); 85 | this.uxTimestampLabel.Name = "uxTimestampLabel"; 86 | this.uxTimestampLabel.Size = new System.Drawing.Size(61, 13); 87 | this.uxTimestampLabel.TabIndex = 6; 88 | this.uxTimestampLabel.Text = "Timestamp:"; 89 | // 90 | // uxCopyToClipboard 91 | // 92 | this.uxCopyToClipboard.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 93 | this.uxCopyToClipboard.Location = new System.Drawing.Point(256, 127); 94 | this.uxCopyToClipboard.Name = "uxCopyToClipboard"; 95 | this.uxCopyToClipboard.Size = new System.Drawing.Size(116, 23); 96 | this.uxCopyToClipboard.TabIndex = 4; 97 | this.uxCopyToClipboard.Text = "Copy to clipboard"; 98 | this.uxCopyToClipboard.UseVisualStyleBackColor = true; 99 | this.uxCopyToClipboard.Click += new System.EventHandler(this.uxCopyToClipboard_Click); 100 | // 101 | // uxUseCurrentDate 102 | // 103 | this.uxUseCurrentDate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); 104 | this.uxUseCurrentDate.Location = new System.Drawing.Point(281, 38); 105 | this.uxUseCurrentDate.Name = "uxUseCurrentDate"; 106 | this.uxUseCurrentDate.Size = new System.Drawing.Size(91, 23); 107 | this.uxUseCurrentDate.TabIndex = 2; 108 | this.uxUseCurrentDate.Text = "Use current"; 109 | this.uxUseCurrentDate.UseVisualStyleBackColor = true; 110 | this.uxUseCurrentDate.Click += new System.EventHandler(this.uxUseCurrentDate_Click); 111 | // 112 | // uxName 113 | // 114 | this.uxName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 115 | | System.Windows.Forms.AnchorStyles.Right))); 116 | this.uxName.FormattingEnabled = true; 117 | this.uxName.Location = new System.Drawing.Point(79, 11); 118 | this.uxName.Name = "uxName"; 119 | this.uxName.Size = new System.Drawing.Size(293, 21); 120 | this.uxName.Sorted = true; 121 | this.uxName.TabIndex = 0; 122 | // 123 | // uxUpdate 124 | // 125 | this.uxUpdate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); 126 | this.uxUpdate.AutoSize = true; 127 | this.uxUpdate.Location = new System.Drawing.Point(12, 132); 128 | this.uxUpdate.Name = "uxUpdate"; 129 | this.uxUpdate.Size = new System.Drawing.Size(0, 13); 130 | this.uxUpdate.TabIndex = 8; 131 | this.uxUpdate.Visible = false; 132 | this.uxUpdate.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.uxUpdate_LinkClicked); 133 | // 134 | // MainForm 135 | // 136 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 137 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 138 | this.ClientSize = new System.Drawing.Size(384, 162); 139 | this.Controls.Add(this.uxUpdate); 140 | this.Controls.Add(this.uxName); 141 | this.Controls.Add(this.uxUseCurrentDate); 142 | this.Controls.Add(this.uxCopyToClipboard); 143 | this.Controls.Add(this.uxTimestampLabel); 144 | this.Controls.Add(this.uxTimestamp); 145 | this.Controls.Add(this.uxMessage); 146 | this.Controls.Add(this.uxMessageLabel); 147 | this.Controls.Add(this.uxNameLabel); 148 | this.MinimumSize = new System.Drawing.Size(400, 200); 149 | this.Name = "MainForm"; 150 | this.Text = "Skype Quote Creator"; 151 | this.Load += new System.EventHandler(this.MainForm_Load); 152 | this.ResumeLayout(false); 153 | this.PerformLayout(); 154 | 155 | } 156 | 157 | #endregion 158 | 159 | private System.Windows.Forms.Label uxNameLabel; 160 | private System.Windows.Forms.Label uxMessageLabel; 161 | private System.Windows.Forms.TextBox uxMessage; 162 | private System.Windows.Forms.MaskedTextBox uxTimestamp; 163 | private System.Windows.Forms.Label uxTimestampLabel; 164 | private System.Windows.Forms.Button uxCopyToClipboard; 165 | private System.Windows.Forms.Button uxUseCurrentDate; 166 | private System.Windows.Forms.ComboBox uxName; 167 | private System.Windows.Forms.LinkLabel uxUpdate; 168 | 169 | } 170 | } 171 | 172 | -------------------------------------------------------------------------------- /source/SkypeQuoteCreator/MainForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Specialized; 3 | using System.ComponentModel; 4 | using System.Deployment.Application; 5 | using System.Drawing; 6 | using System.Globalization; 7 | using System.IO; 8 | using System.Text; 9 | using System.Windows.Forms; 10 | using System.Xml; 11 | using System.Xml.Linq; 12 | 13 | namespace SkypeQuoteCreator 14 | { 15 | /// 16 | /// Main form for the application. 17 | /// 18 | internal sealed partial class MainForm : Form 19 | { 20 | /// 21 | /// Unix time epoch. 22 | /// 23 | private static readonly DateTime epoch = 24 | new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); 25 | 26 | /// 27 | /// Initializes a new instance of the MainForm class. 28 | /// 29 | public MainForm() 30 | { 31 | InitializeComponent(); 32 | Font = SystemFonts.MessageBoxFont; 33 | Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath); 34 | } 35 | 36 | /// 37 | /// Handles the Load event for this form. 38 | /// 39 | /// The source of the event. 40 | /// An EventArgs that contains no event data. 41 | private void MainForm_Load(object sender, EventArgs e) 42 | { 43 | Settings.Default.Load(); 44 | 45 | if (String.IsNullOrEmpty(Settings.Default.UserId)) 46 | { 47 | Settings.Default.UserId = Guid.NewGuid().ToString(); 48 | Settings.Default.Save(); 49 | } 50 | 51 | UseCurrentDate(); 52 | UseCachedNames(); 53 | CheckForUpdates(); 54 | 55 | Analytics.TrackScreenView("Main", Settings.Default.UserId); 56 | } 57 | 58 | /// 59 | /// Checks for any ClickOnce updates. 60 | /// 61 | private void CheckForUpdates() 62 | { 63 | if (ApplicationDeployment.IsNetworkDeployed) 64 | { 65 | ApplicationDeployment deployment = ApplicationDeployment.CurrentDeployment; 66 | deployment.CheckForUpdateCompleted += CheckForUpdateCompleted; 67 | deployment.UpdateProgressChanged += UpdateProgressChanged; 68 | deployment.UpdateCompleted += UpdateCompleted; 69 | 70 | try 71 | { 72 | deployment.CheckForUpdateAsync(); 73 | } 74 | catch (Exception ex) 75 | { 76 | if (ex is InvalidOperationException || 77 | ex is InvalidDeploymentException || 78 | ex is DeploymentDownloadException) 79 | { 80 | // Swallow. 81 | } 82 | else 83 | { 84 | throw; 85 | } 86 | } 87 | } 88 | } 89 | 90 | /// 91 | /// Handles the CheckForUpdateCompleted event. 92 | /// 93 | /// The source of the event. 94 | /// A CheckForUpdateCompletedEventArgs that contains the event data. 95 | private void CheckForUpdateCompleted(object sender, CheckForUpdateCompletedEventArgs e) 96 | { 97 | if (ApplicationDeployment.IsNetworkDeployed) 98 | { 99 | if (e.UpdateAvailable) 100 | { 101 | uxUpdate.Text = "Update available."; 102 | uxUpdate.Visible = true; 103 | } 104 | } 105 | } 106 | 107 | /// 108 | /// Handles the UpdateProgressChanged event. 109 | /// 110 | /// The source of the event. 111 | /// A DeploymentProgressChangedEventArgs that contains the event data. 112 | private void UpdateProgressChanged(object sender, DeploymentProgressChangedEventArgs e) 113 | { 114 | uxUpdate.Text = String.Format( 115 | "{0:D}K out of {1:D}K downloaded - {2:D}% complete", 116 | e.BytesCompleted / 1024, 117 | e.BytesTotal / 1024, 118 | e.ProgressPercentage); 119 | } 120 | 121 | /// 122 | /// Handles the UpdateCompleted event. 123 | /// 124 | /// The source of the event. 125 | /// An AsyncCompletedEventArgs that contains the event data. 126 | private void UpdateCompleted(object sender, AsyncCompletedEventArgs e) 127 | { 128 | uxUpdate.Text = "Update will be applied next time program runs."; 129 | } 130 | 131 | /// 132 | /// Handles the Click event for uxUseCurrentDate. 133 | /// 134 | /// The source of the event. 135 | /// An EventArgs that contains no event data. 136 | private void uxUseCurrentDate_Click(object sender, EventArgs e) 137 | { 138 | UseCurrentDate(); 139 | } 140 | 141 | /// 142 | /// Handles the Click event for uxCopyToClipboard. 143 | /// 144 | /// The source of the event. 145 | /// An EventArgs that contains no event data. 146 | private void uxCopyToClipboard_Click(object sender, EventArgs e) 147 | { 148 | SaveCurrentNameToCache(); 149 | UseCachedNames(); 150 | SaveToClipboard(); 151 | } 152 | 153 | /// 154 | /// Handles the LinkClicked event for uxUpdate. 155 | /// 156 | /// The source of the event. 157 | /// A LinkLabelLinkClickedEventArgs that contains the event data. 158 | private void uxUpdate_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) 159 | { 160 | uxUpdate.Enabled = false; 161 | if (ApplicationDeployment.IsNetworkDeployed) 162 | { 163 | ApplicationDeployment deployment = ApplicationDeployment.CurrentDeployment; 164 | deployment.UpdateAsync(); 165 | } 166 | } 167 | 168 | /// 169 | /// Saves the current name to the name cache. 170 | /// 171 | private void SaveCurrentNameToCache() 172 | { 173 | string name = uxName.Text; 174 | 175 | if (!Settings.Default.NameHistory.Contains(name)) 176 | { 177 | Settings.Default.NameHistory.Add(name); 178 | Settings.Default.Save(); 179 | } 180 | } 181 | 182 | /// 183 | /// Populates the items in uxName with the saved names. 184 | /// 185 | private void UseCachedNames() 186 | { 187 | uxName.Items.Clear(); 188 | 189 | foreach (string name in Settings.Default.NameHistory) 190 | { 191 | uxName.Items.Add(name); 192 | } 193 | } 194 | 195 | /// 196 | /// Populates the Timestamp field with the current date. 197 | /// 198 | private void UseCurrentDate() 199 | { 200 | uxTimestamp.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); 201 | } 202 | 203 | /// 204 | /// Saves the specified message to the clipboard. 205 | /// 206 | private void SaveToClipboard() 207 | { 208 | // Clear the current clipboard. 209 | Clipboard.SetText(" "); 210 | 211 | DateTime dateTime; 212 | 213 | // If the DateTime is invalid, we'll just stop right here. 214 | if (!DateTime.TryParse(uxTimestamp.Text, out dateTime)) 215 | return; 216 | 217 | string user = uxName.Text; 218 | string message = uxMessage.Text; 219 | string skypeMessageFragment = new XDocument( 220 | new XElement("quote", 221 | new XAttribute("author", user), 222 | new XAttribute("authorname", user), 223 | new XAttribute("timestamp", (dateTime.ToUniversalTime() - epoch).TotalSeconds), 224 | message)).ToString(); 225 | 226 | IDataObject dataObject = new DataObject(); 227 | dataObject.SetData("System.String", message); 228 | dataObject.SetData("Text", message); 229 | dataObject.SetData("UnicodeText", message); 230 | dataObject.SetData("OEMText", message); 231 | 232 | dataObject.SetData("SkypeMessageFragment", 233 | new MemoryStream(Encoding.UTF8.GetBytes(skypeMessageFragment))); 234 | 235 | dataObject.SetData("Locale", 236 | new MemoryStream(BitConverter.GetBytes(CultureInfo.CurrentCulture.LCID))); 237 | 238 | Clipboard.SetDataObject(dataObject); 239 | } 240 | } 241 | } 242 | --------------------------------------------------------------------------------