User:John Ericson/AutoWikiBrowserHttpAuthAndSslToCustomProjects.patch

Adds features:

  • Add HTTP AUTH support for Wiki sites that are protected with for example a .htaccess file. A login dialog is displayed for entering username and password if the webserver returnes a HTTP 401 Unauthorized status code.
  • Also added SSL support to CustomProjects which allowes you to visit https:// sites. This is done by checking the "Use secure server" setting in Preferences.

Works with latest trunk of AutoWikiBrowser.

Index: AWB/AutoWikiBrowser.csproj
===================================================================
--- AWB/AutoWikiBrowser.csproj	(revision 7941)
+++ AWB/AutoWikiBrowser.csproj	(working copy)
@@ -100,6 +100,12 @@
     <Compile Include="ExitQuestion.Designer.cs">
       <DependentUpon>ExitQuestion.cs</DependentUpon>
     </Compile>
+    <Compile Include="Login.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="Login.Designer.cs">
+      <DependentUpon>Login.cs</DependentUpon>
+    </Compile>
     <Compile Include="TalkMessage.cs">
       <SubType>Form</SubType>
     </Compile>
@@ -184,6 +190,9 @@
       <SubType>Designer</SubType>
       <DependentUpon>CustomModule.cs</DependentUpon>
     </EmbeddedResource>
+    <EmbeddedResource Include="Login.resx">
+      <DependentUpon>Login.cs</DependentUpon>
+    </EmbeddedResource>
     <EmbeddedResource Include="TalkMessage.resx">
       <SubType>Designer</SubType>
       <DependentUpon>TalkMessage.cs</DependentUpon>
Index: AWB/Login.cs
===================================================================
--- AWB/Login.cs	(revision 0)
+++ AWB/Login.cs	(revision 0)
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Text;
+using System.Windows.Forms;
+using WikiFunctions;
+
+namespace AutoWikiBrowser
+{
+    internal sealed partial class Login : Form
+    {
+        public Login()
+        {
+            InitializeComponent();
+		}
+
+		private void FormOnKeyUp(object sender, KeyEventArgs e)
+		{
+			if (e.KeyCode == Keys.Enter) {
+				CloseForm();
+			}
+		}
+
+        private void label1_Click(object sender, EventArgs e)
+        {
+
+        }
+
+        private void label2_Click(object sender, EventArgs e)
+        {
+
+        }
+
+		private void btnLogin_Click(object sender, EventArgs e)
+		{
+			CloseForm();
+		}
+
+		private void CloseForm() {
+			Variables.HttpAuthUsername = txtUsername.Text;
+			Variables.HttpAuthPassword = txtPassword.Text;
+			Close();
+		}
+
+		private void Login_Load(object sender, EventArgs e) {
+
+		}
+    }
+}
Index: AWB/Login.Designer.cs
===================================================================
--- AWB/Login.Designer.cs	(revision 0)
+++ AWB/Login.Designer.cs	(revision 0)
@@ -0,0 +1,127 @@
+namespace AutoWikiBrowser
+{
+    partial class Login
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+			this.txtUsername = new System.Windows.Forms.TextBox();
+			this.lblDescription = new System.Windows.Forms.Label();
+			this.lblUsername = new System.Windows.Forms.Label();
+			this.lblPassword = new System.Windows.Forms.Label();
+			this.txtPassword = new System.Windows.Forms.TextBox();
+			this.btnLogin = new System.Windows.Forms.Button();
+			this.SuspendLayout();
+			// 
+			// txtUsername
+			// 
+			this.txtUsername.Location = new System.Drawing.Point(93, 62);
+			this.txtUsername.Name = "txtUsername";
+			this.txtUsername.Size = new System.Drawing.Size(152, 20);
+			this.txtUsername.TabIndex = 0;
+			this.txtUsername.KeyUp += new System.Windows.Forms.KeyEventHandler(this.FormOnKeyUp);
+			// 
+			// lblDescription
+			// 
+			this.lblDescription.Location = new System.Drawing.Point(12, 9);
+			this.lblDescription.Name = "lblDescription";
+			this.lblDescription.Size = new System.Drawing.Size(260, 39);
+			this.lblDescription.TabIndex = 1;
+			this.lblDescription.Text = "This wiki is protected using HTTP AUTH. Please login to proceed.";
+			this.lblDescription.Click += new System.EventHandler(this.label1_Click);
+			// 
+			// lblUsername
+			// 
+			this.lblUsername.AutoSize = true;
+			this.lblUsername.Location = new System.Drawing.Point(23, 62);
+			this.lblUsername.Name = "lblUsername";
+			this.lblUsername.Size = new System.Drawing.Size(58, 13);
+			this.lblUsername.TabIndex = 2;
+			this.lblUsername.Text = "Username:";
+			this.lblUsername.Click += new System.EventHandler(this.label2_Click);
+			// 
+			// lblPassword
+			// 
+			this.lblPassword.AutoSize = true;
+			this.lblPassword.Location = new System.Drawing.Point(23, 95);
+			this.lblPassword.Name = "lblPassword";
+			this.lblPassword.Size = new System.Drawing.Size(56, 13);
+			this.lblPassword.TabIndex = 4;
+			this.lblPassword.Text = "Password:";
+			// 
+			// txtPassword
+			// 
+			this.txtPassword.Location = new System.Drawing.Point(93, 95);
+			this.txtPassword.Name = "txtPassword";
+			this.txtPassword.PasswordChar = '*';
+			this.txtPassword.Size = new System.Drawing.Size(153, 20);
+			this.txtPassword.TabIndex = 3;
+			this.txtPassword.KeyUp += new System.Windows.Forms.KeyEventHandler(this.FormOnKeyUp);
+			// 
+			// btnLogin
+			// 
+			this.btnLogin.Location = new System.Drawing.Point(170, 140);
+			this.btnLogin.Name = "btnLogin";
+			this.btnLogin.Size = new System.Drawing.Size(75, 23);
+			this.btnLogin.TabIndex = 5;
+			this.btnLogin.Text = "Login";
+			this.btnLogin.UseVisualStyleBackColor = true;
+			this.btnLogin.Click += new System.EventHandler(this.btnLogin_Click);
+			// 
+			// Login
+			// 
+			this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+			this.ClientSize = new System.Drawing.Size(259, 175);
+			this.Controls.Add(this.btnLogin);
+			this.Controls.Add(this.lblPassword);
+			this.Controls.Add(this.txtPassword);
+			this.Controls.Add(this.lblUsername);
+			this.Controls.Add(this.lblDescription);
+			this.Controls.Add(this.txtUsername);
+			this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+			this.MaximizeBox = false;
+			this.MinimizeBox = false;
+			this.Name = "Login";
+			this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+			this.Text = "Login";
+			this.Load += new System.EventHandler(this.Login_Load);
+			this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.FormOnKeyUp);
+			this.ResumeLayout(false);
+			this.PerformLayout();
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.TextBox txtUsername;
+        private System.Windows.Forms.Label lblDescription;
+        private System.Windows.Forms.Label lblUsername;
+        private System.Windows.Forms.Label lblPassword;
+        private System.Windows.Forms.TextBox txtPassword;
+        private System.Windows.Forms.Button btnLogin;
+    }
+}
\ No newline at end of file
Index: AWB/Login.resx
===================================================================
--- AWB/Login.resx	(revision 0)
+++ AWB/Login.resx	(revision 0)
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
\ No newline at end of file
Index: AWB/Main.cs
===================================================================
--- AWB/Main.cs	(revision 7941)
+++ AWB/Main.cs	(working copy)
@@ -44,6 +44,7 @@
 using WikiFunctions.Controls.Lists;
 using AutoWikiBrowser.Plugins;
 using System.Web;
+using System.Net;
 
 namespace AutoWikiBrowser
 {
@@ -2863,9 +2864,29 @@
             SplashScreen.SetProgress(81);
             try
             {
-                //set namespaces
-                Variables.SetProject(code, project, customProject, usingSecure);
+                try
+                {
+                    //set namespaces
+                    Variables.SetProject(code, project, customProject, usingSecure);
+                }
+                catch (WebException ex) {
+					// Check for HTTP 401 error.
+					var resp = (HttpWebResponse)ex.Response;
+					if (resp == null) throw;
+					switch (resp.StatusCode) {
+						case HttpStatusCode.Unauthorized /*401*/:
+							ShowLogin();
+							
+							// Reload project.
+							Variables.SetProject(code, project, customProject, usingSecure);
 
+							break;
+					}
+                }
+                catch (Exception) {
+					throw;
+				}
+
                 if (Variables.TryLoadingAgainAfterLogin)
                 {
                     MessageBox.Show(
@@ -4716,6 +4737,12 @@
             chkMinor.Checked = markAllAsMinorToolStripMenuItem.Checked;
         }
 
+        private void ShowLogin()
+        {
+            Login login = new Login();
+            login.ShowDialog(this);
+		}
+
         #region Shutdown
         private void chkShutdown_CheckedChanged(object sender, EventArgs e)
         {
Index: AWB/Preferences.cs
===================================================================
--- AWB/Preferences.cs	(revision 7941)
+++ AWB/Preferences.cs	(working copy)
@@ -63,6 +63,7 @@
             cmboCustomProject.Text = customproj;
             
             PrefUsingSecure = usingSecure;
+			chkUsingSecure.Enabled = (cmboProject.Text != "wikia" ? true : false);
 
             PrefPHP5 = usePHP5;
 
@@ -187,8 +188,13 @@
                 cmboCustomProjectChanged(null, null);
 
                 chkSupressAWB.Enabled = true;
-                chkUsingSecure.Enabled = chkUsingSecure.Checked = false;
 
+				// Custom server can be SSL enabled.
+				if (prj == ProjectEnum.wikia)
+				{
+					chkUsingSecure.Enabled = chkUsingSecure.Checked = false;
+				}
+
                 chkPHP5Ext.Enabled = (prj == ProjectEnum.custom);
 
                 return;
Index: WikiFunctions/API/ApiEdit.cs
===================================================================
--- WikiFunctions/API/ApiEdit.cs	(revision 7941)
+++ WikiFunctions/API/ApiEdit.cs	(working copy)
@@ -25,6 +25,7 @@
 using System.Xml;
 using System.Threading;
 using System.Text.RegularExpressions;
+using System.Security.Cryptography.X509Certificates;
 
 namespace WikiFunctions.API
 {
@@ -70,7 +71,7 @@
             : this()
         {
             if (string.IsNullOrEmpty(url)) throw new ArgumentException("Invalid URL specified", "url");
-            if (!url.StartsWith("http://")) throw new NotSupportedException("Only editing via HTTP is currently supported");
+            //if (!url.StartsWith("http://")) throw new NotSupportedException("Only editing via HTTP is currently supported");
 
             URL = url;
             PHP5 = usePHP5;
@@ -317,6 +318,14 @@
                                                                  Environment.OSVersion.VersionString,
                                                                  Environment.Version);
 
+
+        private static bool customXertificateValidation(object sender, X509Certificate cert, X509Chain chain, System.Net.Security.SslPolicyErrors error)
+        {
+            // TODO: Implement better validation. JOE 20110722
+			return true;
+        }
+
+        
         /// <summary>
         /// 
         /// </summary>
@@ -327,6 +336,7 @@
             if (Globals.UnitTestMode) throw new Exception("You shouldn't access Wikipedia from unit tests");
 
             ServicePointManager.Expect100Continue = false;
+            ServicePointManager.ServerCertificateValidationCallback += new System.Net.Security.RemoteCertificateValidationCallback(customXertificateValidation);
             HttpWebRequest res = (HttpWebRequest)WebRequest.Create(url);
             res.ServicePoint.Expect100Continue = false;
             res.Expect = "";
@@ -356,6 +366,17 @@
         {
             Request = req;
 
+            NetworkCredential login = new NetworkCredential();
+			login.UserName = Variables.HttpAuthUsername;
+			login.Password = Variables.HttpAuthPassword;
+            //login.Domain = "";
+			
+			CredentialCache myCache = new CredentialCache();
+			myCache.Add(new Uri(URL), "Basic", login);
+			req.Credentials = myCache;
+
+			req = (HttpWebRequest)SetBasicAuthHeader(req, login.UserName, login.Password);
+
             try
             {
                 using (WebResponse resp = req.GetResponse())
@@ -372,7 +393,10 @@
                 if (resp == null) throw;
                 switch (resp.StatusCode)
                 {
-                    case HttpStatusCode.NotFound /*404*/:
+					case HttpStatusCode.Unauthorized: // 401						
+						break;
+
+					case HttpStatusCode.NotFound: // 404
                         return ""; // emulate the behaviour of Tools.HttpGet()
                 }
 
@@ -395,6 +419,14 @@
         private string[,] lastPostParameters;
         private string lastGetUrl;
 
+		// Source: http://blog.kowalczyk.info/article/Forcing-basic-http-authentication-for-HttpWebReq.html
+		protected WebRequest SetBasicAuthHeader(WebRequest req, String userName, String userPassword) {
+			string authInfo = userName + ":" + userPassword;
+			authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
+			req.Headers["Authorization"] = "Basic " + authInfo;
+			return req;
+		}
+
         /// <summary>
         /// 
         /// </summary>
Index: WikiFunctions/Session.cs
===================================================================
--- WikiFunctions/Session.cs	(revision 7941)
+++ WikiFunctions/Session.cs	(working copy)
@@ -22,6 +22,8 @@
 using System.Text.RegularExpressions;
 using System.Windows.Forms;
 using WikiFunctions.API;
+using System.Net;
+using System.Security.Authentication;
 
 namespace WikiFunctions
 {
@@ -192,8 +194,20 @@
             {
                 throw;
             }
-            catch
+            catch (WebException ex)
             {
+                // Check for HTTP 401 error.                
+                var resp = (HttpWebResponse)ex.Response;
+                if (resp == null) throw;
+                switch (resp.StatusCode)
+                {
+                    case HttpStatusCode.Unauthorized /*401*/:
+                        throw;
+                }
+                return false;
+            }
+            catch (Exception)
+            {                
                 Editor = CreateEditor("http://en.wikipedia.org/w/", false);
                 return false;
             }
@@ -407,14 +421,71 @@
             {
                 throw;
             }
+            catch (WebException ex)
+            {
+                string message = "";
+                
+                if (ex.InnerException != null)
+                {
+                    if (ex.InnerException is AuthenticationException)
+                    {
+
+                        if (message.Equals(""))
+                        {
+                            message = ex.Message;
+                        }
+                        else
+                        {
+                            message += " " + ex.Message;
+                        }
+                    }
+
+                    if (message.Equals(""))
+                    {
+                        message = ex.InnerException.Message;
+                    }
+                    else
+                    {
+                        message += " " + ex.InnerException.Message;
+                    }
+                }
+                else
+                {
+                    var resp = (HttpWebResponse)ex.Response;
+                    if (resp == null) throw;
+
+                    // Check for HTTP 401 error.
+                    switch (resp.StatusCode)
+                    {
+                        case HttpStatusCode.Unauthorized: // 401
+                            throw;
+                    }
+                    
+                    message = ex.Message;
+                }
+
+                MessageBox.Show(message, "Error connecting to wiki", MessageBoxButtons.OK, MessageBoxIcon.Error);
+                
+                throw ex;
+            }
             catch (Exception ex)
             {
                 //TODO:Better error handling
 
-                string message = ex is WikiUrlException && ex.InnerException != null
-                    ? ex.InnerException.Message
-                    : ex.Message;
+                string message = "";
 
+                if (ex is WikiUrlException)
+                {
+                    if (ex.InnerException != null)
+                    {
+                        message = ex.InnerException.Message;
+                    }
+                }
+                else
+                {
+                    message = ex.Message;
+                }
+
                 MessageBox.Show("An error occured while connecting to the server or loading project information from it. " +
                         "Please make sure that your internet connection works and such combination of project/language exist." +
                         "\r\nEnter the URL in the format \"en.wikipedia.org/w/\" (including path where index.php and api.php reside)." +
Index: WikiFunctions/SiteInfo.cs
===================================================================
--- WikiFunctions/SiteInfo.cs	(revision 7941)
+++ WikiFunctions/SiteInfo.cs	(working copy)
@@ -20,6 +20,7 @@
 using System.Collections.Generic;
 using System.Xml;
 using System.Xml.Serialization;
+using System.Net;
 using WikiFunctions.API;
 
 namespace WikiFunctions
@@ -71,6 +72,10 @@
             {
                 throw;
             }
+            catch (WebException)
+            {
+                throw;
+            }
             catch (Exception ex)
             {
                 throw new WikiUrlException(ex);
@@ -289,16 +294,20 @@
         #region Helpers
         public void OpenPageInBrowser(string title)
         {
-            if (!Variables.UsingSecure && ArticleUrl.Contains("$1"))
+			if (Variables.IsCustomProject && ArticleUrl.Contains("$1"))
             {
                 string url = ArticleUrl.Replace("$1", Tools.WikiEncode(title));
 
                 Tools.OpenURLInBrowser(url);
             }
-            else
-            {
-                Tools.OpenArticleInBrowser(title);
-            }
+			else if (!Variables.UsingSecure && ArticleUrl.Contains("$1")) {
+				string url = ArticleUrl.Replace("$1", Tools.WikiEncode(title));
+
+				Tools.OpenURLInBrowser(url);
+			}
+			else {
+				Tools.OpenArticleInBrowser(title);
+			}
         }
 
         public void OpenPageHistoryInBrowser(string title)
Index: WikiFunctions/Variables.cs
===================================================================
--- WikiFunctions/Variables.cs	(revision 7941)
+++ WikiFunctions/Variables.cs	(working copy)
@@ -156,7 +156,7 @@
         /// Gets a Index URL of the site, e.g. "http://en.wikipedia.org/w/index.php"
         /// </summary>
         public static string URLIndex
-        { get { return (UsingSecure ? URLSecure + URLEnd : URLLong) + IndexPHP; } }
+        { get { return (UsingSecure && !IsCustomProject ? URLSecure + URLEnd : URLLong) + IndexPHP; } }
 
         /// <summary>
         /// Gets a Index URL of the site, e.g. "http://en.wikipedia.org/w/api.php"
@@ -164,6 +164,16 @@
         public static string URLApi
         { get { return URLLong + ApiPHP; } }
 
+		public static string HttpAuthUsername {
+			get;
+			set;
+		}
+
+		public static string HttpAuthPassword {
+			get;
+			set;
+		}
+		
         /// <summary>
         /// true if current wiki uses right-to-left writing system
         /// </summary>
@@ -505,6 +515,7 @@
             if (IsCustomProject)
             {
                 LangCode = "en";
+				URLEnd = "";
                 int x = customProject.IndexOf('/');
 
                 if (x > 0)
@@ -513,7 +524,8 @@
                     CustomProject = customProject.Substring(0, x);
                 }
 
-                URL = "http://" + CustomProject;
+				URL = (usingSecure ? "https://" : "http://") + CustomProject;
+
             }
             else
             {
@@ -683,7 +695,10 @@
                     URLEnd = "/";
                     break;
                 case ProjectEnum.custom:
-                    //URLEnd = "";
+					// Make sure URL ends with / so ApiURL won't become www.customwiki.comapi.php.
+					if (!URL.EndsWith("/")) {
+						URLEnd = "/";
+					}
                     break;
             }
 
@@ -693,27 +708,26 @@
             //HACK:HACK:HACK:HACK:HACK:
             if (MainForm != null && MainForm.TheSession != null)
             {
-                try
-                {
-                    if (!MainForm.TheSession.UpdateProject(false))
-                    {
-                        LangCode = "en";
-                        Project = ProjectEnum.wikipedia;
-                        SetToEnglish();
-                    }
-                }
-                catch (ReadApiDeniedException)
-                {
-                    TryLoadingAgainAfterLogin = true;
-                    ReloadProjectSettings = new ProjectHoldArea
-                                                {
-                                                    projectName = projectName,
-                                                    customProject = customProject,
-                                                    langCode = langCode,
-                                                    usingSecure = usingSecure
-                                                };
-                    return;
-                }
+				try {
+					if (!MainForm.TheSession.UpdateProject(false)) {
+						LangCode = "en";
+						Project = ProjectEnum.wikipedia;
+						SetToEnglish();
+					}
+				}
+				catch (ReadApiDeniedException) {
+					TryLoadingAgainAfterLogin = true;
+					ReloadProjectSettings = new ProjectHoldArea {
+						projectName = projectName,
+						customProject = customProject,
+						langCode = langCode,
+						usingSecure = usingSecure
+					};
+					return;
+				}
+				catch (Exception ex) {
+					throw ex;
+				}
             }
 
             RegenerateRegexes();

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.