diff --git a/ChangeLog b/ChangeLog
index 05a5e94..33a3caa 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -77,3 +77,40 @@ Changes
Fix problems when path settings have trailing (back-)slashes.
Support for Python 3.x, PyQt 4.6+ and OpenSSL 1.x
Enable server authentication for better security (Python 3.2+ only currently)
+
+0.2.1 Fixes for launcher.config XML Changes and version bump to 0.2.1
+ Fix for 20-Nov-2014 slight changes to WorldQueue.config by Turbine which
+ broke pylotro.
+
+0.2.2 Fixes for Update 15.1 changes to launcher.config argument template. Turbine is now
+ using crashserverurl and DefaultUploadThrottleMbps in the argument template.
+ Version bump to 0.2.2.
+
+0.2.3 Localization changes from hcjiv1 and Arek75. Turbine has removed the client local
+ files for each language. Now each language has a separate subdirectory. If
+ the client local file is not found then I (hcjiv1) pick languages based on those
+ subdirectories. Thanks to hcjiv1 and Arek75. Version bump to 0.2.3
+
+0.2.4 News feed fixed - Apparently Turbine changed the content encoding of the news feed to
+ gzip and retrieving the news feed was failing. We now accept gzip content
+ encoding for the news feed by default and check the Content-Encoding header and
+ uncompress if content is gzip.
+ Also some palette adjustments to the widgets (darker theme)
+
+0.2.5 Added code to check for local game client override in TurbineLauncher.exe.config in game
+ directory. This is to handle workaround from SSG for game client crashes on
+ Windows XP/Vista platforms that also affects Linux users running the game under
+ wine. For more information see link below.
+
+ https://www.lotro.com/forums/showthread.php?654273-Windows-XP-and-Vista-Launcher-Issues-Solution
+
+0.2.6 Updated certificate chain to new SSL certificates after recent update (22.0.1 or possibly 22) update
+ by SSG broke authentication using the old certs.
+
+0.2.7 Added option in Game Settings to select which game client to use.
+ The choices are 32-bit, 32-bit Legacy ("Awesomium"), and 64-bit. The 32-bit
+ Legacy Awesomium client is recommended for Linux users. Game client override
+ code that checked TurbineLauncher.exe.config has been removed since it is no
+ longer needed with this option.
+
+0.2.8 Updated certificate chain after game update 29.5 invalidated old certs.
diff --git a/PyLotRO.iss b/PyLotRO.iss
index 08fd992..994adaf 100755
--- a/PyLotRO.iss
+++ b/PyLotRO.iss
@@ -7,7 +7,7 @@
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{EB42F98E-B61B-4EE7-AF06-CAAF8D1825A3}
AppName=PyLotRO
-AppVerName=PyLotRO 0.2.0
+AppVerName=PyLotRO 0.2.8
AppPublisher=AJackson
AppPublisherURL=http://www.lotrolinux.com
AppSupportURL=http://www.lotrolinux.com
diff --git a/PyLotROLauncher/CheckConfig.py b/PyLotROLauncher/CheckConfig.py
index d9da51c..dd98685 100644
--- a/PyLotROLauncher/CheckConfig.py
+++ b/PyLotROLauncher/CheckConfig.py
@@ -40,6 +40,7 @@ def __init__(self, parent, settings, homeDir, osType, rootDir):
self.osType = osType
self.winCheckConfig = QtGui.QDialog(parent)
+ self.winCheckConfig.setPalette(parent.palette())
uifile = None
diff --git a/PyLotROLauncher/Information.py b/PyLotROLauncher/Information.py
index 12a2c59..e652d19 100644
--- a/PyLotROLauncher/Information.py
+++ b/PyLotROLauncher/Information.py
@@ -1,5 +1,5 @@
# coding=utf-8
-Version = "0.2.0"
+Version = "0.2.8"
Description = "LOTRO/DDO Launcher"
Author = "Alan Jackson"
Email = "ajackson@bcs.org.uk"
diff --git a/PyLotROLauncher/MainWindow.py b/PyLotROLauncher/MainWindow.py
index 7c17a48..80ab829 100644
--- a/PyLotROLauncher/MainWindow.py
+++ b/PyLotROLauncher/MainWindow.py
@@ -30,6 +30,7 @@
import os
import sys
import xml.dom.minidom
+import zlib
from PyQt4 import QtCore, QtGui, uic
from .SettingsWindow import SettingsWindow
from .SettingsWizard import SettingsWizard
@@ -83,6 +84,30 @@ def __init__(self):
self.uiMain = Ui_winMain()
self.uiMain.setupUi(self.winMain)
+ # Set window palette
+ self.palette = QtGui.QPalette()
+ self.palette.setColor(QtGui.QPalette.Base, QtCore.Qt.black)
+ self.palette.setColor(QtGui.QPalette.AlternateBase, QtGui.QColor(22,21,21))
+ self.palette.setColor(QtGui.QPalette.ToolTipBase, QtGui.QColor(255,255,220))
+ self.palette.setColor(QtGui.QPalette.ToolTipText, QtCore.Qt.black)
+ self.palette.setColor(QtGui.QPalette.Window, QtGui.QColor(44,43,42))
+ self.palette.setColor(QtGui.QPalette.WindowText, QtCore.Qt.white)
+ self.palette.setColor(QtGui.QPalette.Text, QtCore.Qt.white)
+ self.palette.setColor(QtGui.QPalette.BrightText, QtCore.Qt.white)
+ self.palette.setColor(QtGui.QPalette.ButtonText, QtCore.Qt.white)
+ self.palette.setColor(QtGui.QPalette.Button, QtGui.QColor(44,43,42))
+ self.winMain.setPalette(self.palette)
+
+ # find menubar object and save it so we can find the menus
+ for child in self.winMain.children():
+ if isinstance(child, QtGui.QMenuBar):
+ self.menubar = child
+
+ # find menu objects and set the palette on them
+ for child in self.menubar.children():
+ if isinstance(child, QtGui.QMenu):
+ child.setPalette(self.palette)
+
self.webMainExists = True
try:
self.webMain = QtWebKit.QWebView(self.uiMain.centralwidget)
@@ -162,6 +187,7 @@ def actionCheckSelected(self):
def actionAboutSelected(self):
dlgAbout = QtGui.QDialog(self.winMain)
+ dlgAbout.setPalette(self.winMain.palette())
uifile = None
@@ -198,11 +224,13 @@ def actionPatchSelected(self):
def actionOptionsSelected(self):
winSettings = SettingsWindow(self.winMain, self.settings.hiResEnabled, self.settings.app,
self.settings.wineProg, self.settings.wineDebug, self.settings.patchClient,
- self.settings.winePrefix, self.settings.gameDir, self.valHomeDir, self.osType, self.rootDir)
+ self.settings.winePrefix, self.settings.gameDir, self.valHomeDir, self.osType, self.rootDir,
+ self.settings.gameClientIdx)
self.hideWinMain()
if winSettings.Run() == QtGui.QDialog.Accepted:
self.settings.hiResEnabled = winSettings.getHiRes()
+ self.settings.gameClientIdx = winSettings.getGameClientIdx()
self.settings.app = winSettings.getApp()
self.settings.patchClient = winSettings.getPatchClient()
self.settings.gameDir = winSettings.getGameDir()
@@ -226,6 +254,7 @@ def actionWizardSelected(self):
self.settings.usingDND = winWizard.getUsingDND()
self.settings.usingTest = winWizard.getUsingTest()
self.settings.hiResEnabled = winWizard.getHiRes()
+ self.settings.gameClientIdx = winSettings.getGameClientIdx()
self.settings.app = winWizard.getApp()
self.settings.wineProg = winWizard.getProg()
self.settings.wineDebug = winWizard.getDebug()
@@ -240,6 +269,7 @@ def actionWizardSelected(self):
def actionSwitchSelected(self):
dlgChooseAccount = QtGui.QDialog(self.winMain)
+ dlgChooseAccount.setPalette(self.winMain.palette())
uifile = None
@@ -360,13 +390,28 @@ def AuthAccount(self):
self.AddLog(self.account.messError)
def LaunchGame(self):
- game = StartGame(self.winMain, self.worldQueueConfig.gameClientFilename,
+ gameClientIdx = int(self.settings.gameClientIdx)
+
+ if gameClientIdx == 0:
+ gameClientFilename = self.worldQueueConfig.gameClientFilename32
+ elif gameClientIdx == 1:
+ gameClientFilename = self.worldQueueConfig.gameClientFilenameLegacy
+ elif gameClientIdx == 2:
+ gameClientFilename = "x64/" + self.worldQueueConfig.gameClientFilename64
+
+ game = StartGame(self.winMain, gameClientFilename,
self.worldQueueConfig.gameClientArgTemplate, self.accNumber, self.urlLoginServer,
self.account.ticket, self.urlChatServer,
self.langConfig.langList[self.uiMain.cboLanguage.currentIndex()].code,
self.settings.gameDir, self.settings.wineProg, self.settings.wineDebug,
self.settings.winePrefix, self.settings.hiResEnabled, self.settings.app,
- self.osType, self.valHomeDir, self.gameType.icoFile, self.rootDir)
+ self.osType, self.valHomeDir, self.gameType.icoFile, self.rootDir,
+ self.worldQueueConfig.crashreceiver, self.worldQueueConfig.DefaultUploadThrottleMbps,
+ self.worldQueueConfig.bugurl, self.worldQueueConfig.authserverurl,
+ self.worldQueueConfig.supporturl, self.worldQueueConfig.supportserviceurl,
+ self.worldQueueConfig.glsticketlifetime,
+ self.uiMain.cboRealm.currentText(),
+ self.uiMain.txtAccount.text())
self.winMain.hide()
game.Run()
@@ -618,7 +663,7 @@ def AccessGLSDataCentre(self, urlGLS, gameName):
QtCore.QObject.emit(self.winMain, QtCore.SIGNAL("AddLog(QString)"), "[E04] Error accessing GLS data centre.")
def GetWorldQueueConfig(self, urlWorldQueueServer):
- self.worldQueueConfig = WorldQueueConfig(urlWorldQueueServer, self.settings.usingDND, self.baseDir, self.osType)
+ self.worldQueueConfig = WorldQueueConfig(urlWorldQueueServer, self.settings.usingDND, self.baseDir, self.osType, self.settings.gameDir)
if self.worldQueueConfig.loadSuccess:
QtCore.QObject.emit(self.winMain, QtCore.SIGNAL("AddLog(QString)"), "World queue configuration read")
@@ -636,11 +681,15 @@ def GetNews(self):
webservice, post = WebConnection(self.worldQueueConfig.newsStyleSheetURL)
webservice.putrequest("GET", post)
+ webservice.putheader("Accept-Encoding", "gzip")
webservice.endheaders()
webresp = webservice.getresponse()
- tempxml = webresp.read()
+ if webresp.getheader('Content-Encoding', '') == 'gzip':
+ tempxml = zlib.decompress(webresp.read(), 16+zlib.MAX_WBITS)
+ else:
+ tempxml = webresp.read()
doc = xml.dom.minidom.parseString(tempxml)
@@ -659,6 +708,9 @@ def GetNews(self):
if link.nodeType == link.ELEMENT_NODE:
href = link.attributes["href"]
+ # Ignore broken href (as of 3/30/16) in the style sheet and use Launcher.NewsFeedCSSUrl defined in launcher.config
+ href.value = self.worldQueueConfig.newsFeedCSSURL
+
HTMLTEMPLATE = '
'
@@ -669,18 +721,27 @@ def GetNews(self):
webservice, post = WebConnection(urlNewsFeed)
webservice.putrequest("GET", post)
+ webservice.putheader("Accept-Encoding", "gzip")
webservice.endheaders()
webresp = webservice.getresponse()
- tempxml = webresp.read()
+ if webresp.getheader('Content-Encoding', '') == 'gzip':
+ tempxml = zlib.decompress(webresp.read(), 16+zlib.MAX_WBITS)
+ else:
+ tempxml = webresp.read()
if len(tempxml) == 0:
webservice, post = WebConnection(webresp.getheader("location"))
webservice.putrequest("GET", post)
+ webservice.putheader("Accept-Encoding", "gzip")
webservice.endheaders()
webresp = webservice.getresponse()
- tempxml = webresp.read()
+
+ if webresp.getheader('Content-Encoding', '') == 'gzip':
+ tempxml = zlib.decompress(webresp.read(), 16+zlib.MAX_WBITS)
+ else:
+ tempxml = webresp.read()
result = HTMLTEMPLATE
diff --git a/PyLotROLauncher/PatchWindow.py b/PyLotROLauncher/PatchWindow.py
index fd17341..8257850 100644
--- a/PyLotROLauncher/PatchWindow.py
+++ b/PyLotROLauncher/PatchWindow.py
@@ -40,6 +40,7 @@ def __init__(self, parent, urlPatchServer, prodCode, language, runDir, patchClie
self.winMain = parent
self.homeDir = homeDir
self.winLog = QtGui.QDialog(parent)
+ self.winLog.setPalette(parent.palette())
self.osType = osType
uifile = None
diff --git a/PyLotROLauncher/PyLotROUtils.py b/PyLotROLauncher/PyLotROUtils.py
index c01485e..a3bdae8 100644
--- a/PyLotROLauncher/PyLotROUtils.py
+++ b/PyLotROLauncher/PyLotROUtils.py
@@ -31,11 +31,21 @@
import subprocess
import sys
import glob
+import codecs
from PyQt4 import QtCore
import xml.dom.minidom
from xml.sax.saxutils import escape as xml_escape
import ssl
+# Python 3 on windows needs Turbine-supplied config files
+# to be written in UTF-8, but Python 2 doesn't, and won't
+# convert an ascii string for use in codecs.open()
+if sys.version_info >= (3,):
+ from codecs import open as uopen
+else:
+ def uopen(name, mode, dummy):
+ return open(name, mode)
+
# If Python >3.0 is in use use http otherwise httplib
# Python >3.0 uses unicode strings by default, so also
# need to take care of encoding/decoding for sending/receiving
@@ -340,7 +350,7 @@ def __init__(self, urlGLSDataCentreService, gameName, baseDir, osType):
tempxml = string_decode(webresp.read())
filename = "%s%sGLSDataCenter.config" % (baseDir, osType.appDir)
- outfile = open(filename, "w")
+ outfile = uopen(filename, "w", "utf-8")
outfile.write(tempxml)
outfile.close()
@@ -375,15 +385,18 @@ def __init__(self, urlGLSDataCentreService, gameName, baseDir, osType):
class Language:
def __init__(self, code):
- self.code = code.upper()
+ # make code uppercase for easier testing - don't use self.code here unless you want to test against self.code instead of code.
+ code = code.upper()
self.news = "en"
if code == "EN_GB":
self.name = "English (UK)"
self.code = "ENGLISH"
- elif code == "ENGLISH":
+ self.news = "en"
+ elif code == "ENGLISH" or code == "EN":
self.name = "English"
self.code = "ENGLISH"
+ self.news = "en"
elif code == "FR":
self.name = "French"
self.code = "FR"
@@ -406,6 +419,13 @@ def __init__(self, runDir):
# remove "client_local_" (13 chars) and ".dat" (4 chars) from filename
temp = os.path.basename(name)[13:-4]
self.langList.append(Language(temp))
+ # Handle newer clients where the language is a subdir
+ for name in os.listdir(runDir):
+ path = os.path.join(runDir, name)
+ if os.path.exists(os.path.join(path, "Licenses")):
+ lang = Language(name)
+ self.langList.append(lang)
+ self.langFound = True
class Realm:
def __init__(self, name, urlChatServer, urlServerStatus):
@@ -429,7 +449,7 @@ def CheckRealm(self, useDND, baseDir, osType):
tempxml = string_decode(webresp.read())
filename = "%s%sserver.config" % (baseDir, osType.appDir)
- outfile = open(filename, "w")
+ outfile = uopen(filename, "w", "utf-8")
outfile.write(tempxml)
outfile.close()
@@ -455,9 +475,19 @@ def CheckRealm(self, useDND, baseDir, osType):
self.realmAvailable = False
class WorldQueueConfig:
- def __init__(self, urlConfigServer, usingDND, baseDir, osType):
+ def __init__(self, urlConfigServer, usingDND, baseDir, osType, gameDir):
self.gameClientFilename = ""
+ self.gameClientFilename32 = ""
+ self.gameClientFilename64 = ""
+ self.gameClientFilenameLegacy = ""
self.gameClientArgTemplate = ""
+ self.crashreceiver = ""
+ self.DefaultUploadThrottleMbps = ""
+ self.bugurl = ""
+ self.authserverurl = ""
+ self.supporturl = ""
+ self.supportserviceurl = ""
+ self.glsticketlifetime = ""
self.newsFeedURL = ""
self.newsStyleSheetURL = ""
self.patchProductCode = ""
@@ -475,7 +505,7 @@ def __init__(self, urlConfigServer, usingDND, baseDir, osType):
tempxml = string_decode(webresp.read())
filename = "%s%slauncher.config" % (baseDir, osType.appDir)
- outfile = open(filename, "w")
+ outfile = uopen(filename, "w", "utf-8")
outfile.write(tempxml)
outfile.close()
@@ -487,10 +517,30 @@ def __init__(self, urlConfigServer, usingDND, baseDir, osType):
nodes = doc.getElementsByTagName("appSettings")[0].childNodes
for node in nodes:
if node.nodeType == node.ELEMENT_NODE:
- if node.getAttribute("key") == "GameClient.Filename":
- self.gameClientFilename = node.getAttribute("value")
- elif node.getAttribute("key") == "GameClient.ArgTemplate":
+ if node.getAttribute("key") == "GameClient.WIN32.Filename":
+ self.gameClientFilename32 = node.getAttribute("value")
+ if node.getAttribute("key") == "GameClient.WIN64.Filename":
+ self.gameClientFilename64 = node.getAttribute("value")
+ if node.getAttribute("key") == "GameClient.WIN32Legacy.Filename":
+ self.gameClientFilenameLegacy = node.getAttribute("value")
+ elif node.getAttribute("key") == "GameClient.WIN32.ArgTemplate":
self.gameClientArgTemplate = node.getAttribute("value")
+ elif node.getAttribute("key") == "GameClient.Arg.crashreceiver":
+ self.crashreceiver = node.getAttribute("value")
+ elif node.getAttribute("key") == "GameClient.Arg.DefaultUploadThrottleMbps":
+ self.DefaultUploadThrottleMbps = node.getAttribute("value")
+ elif node.getAttribute("key") == "GameClient.Arg.bugurl":
+ self.bugurl = node.getAttribute("value")
+ elif node.getAttribute("key") == "GameClient.Arg.authserverurl":
+ self.authserverurl = node.getAttribute("value")
+ elif node.getAttribute("key") == "GameClient.Arg.supporturl":
+ self.supporturl = node.getAttribute("value")
+ elif node.getAttribute("key") == "GameClient.Arg.supportserviceurl":
+ self.supportserviceurl = node.getAttribute("value")
+ elif node.getAttribute("key") == "GameClient.Arg.glsticketlifetime":
+ self.glsticketlifetime = node.getAttribute("value")
+ elif node.getAttribute("key") == "Launcher.NewsFeedCSSUrl":
+ self.newsFeedCSSURL = node.getAttribute("value")
elif node.getAttribute("key") == "URL.NewsFeed":
self.newsFeedURL = node.getAttribute("value")
elif node.getAttribute("key") == "URL.NewsStyleSheet":
@@ -505,6 +555,7 @@ def __init__(self, urlConfigServer, usingDND, baseDir, osType):
self.loadSuccess = True
except:
self.loadSuccess = False
+ raise
class Game:
def __init__(self, name, description):
@@ -547,7 +598,7 @@ def __init__(self, urlLoginServer, name, password, game, baseDir, osType):
tempxml = string_decode(webresp.read())
filename = "%s%sGLSAuthServer.config" % (baseDir, osType.appDir)
- outfile = open(filename, "w")
+ outfile = uopen(filename, "w", "utf-8")
outfile.write(tempxml)
outfile.close()
@@ -613,7 +664,7 @@ def __init__(self, argTemplate, account, ticket, queue, urlIn, baseDir, osType):
tempxml = string_decode(webresp.read())
filename = "%s%sWorldQueue.config" % (baseDir, osType.appDir)
- outfile = open(filename, "w")
+ outfile = uopen(filename, "w", "utf-8")
outfile.write(tempxml)
outfile.close()
diff --git a/PyLotROLauncher/Settings.py b/PyLotROLauncher/Settings.py
index 8e8e916..2664ecb 100644
--- a/PyLotROLauncher/Settings.py
+++ b/PyLotROLauncher/Settings.py
@@ -52,6 +52,7 @@ def LoadSettings(self, useGame=None):
self.focusAccount = True
self.winePrefix = os.environ.get('WINEPREFIX')
self.gameDir = ""
+ self.gameClientIdx = 0
self.hideWinMain = False
success = False
@@ -95,6 +96,8 @@ def LoadSettings(self, useGame=None):
self.hiResEnabled = True
else:
self.hiResEnabled = False
+ elif node.nodeName == "Game.Client.Index":
+ self.gameClientIdx = GetText(node.childNodes)
elif node.nodeName == "Game.Directory":
self.gameDir = GetText(node.childNodes)
elif node.nodeName == "Realm":
@@ -191,6 +194,10 @@ def SaveSettings(self, saveAccountDetails):
tempNode.appendChild(doc.createTextNode("%s" % (self.gameDir)))
gameConfigNode.appendChild(tempNode)
+ tempNode = doc.createElementNS(EMPTY_NAMESPACE, "Game.Client.Index")
+ tempNode.appendChild(doc.createTextNode("%s" % (self.gameClientIdx)))
+ gameConfigNode.appendChild(tempNode)
+
tempNode = doc.createElementNS(EMPTY_NAMESPACE, "PatchClient")
tempNode.appendChild(doc.createTextNode("%s" % (self.patchClient)))
gameConfigNode.appendChild(tempNode)
diff --git a/PyLotROLauncher/SettingsWindow.py b/PyLotROLauncher/SettingsWindow.py
index 6caef30..fa6ed20 100644
--- a/PyLotROLauncher/SettingsWindow.py
+++ b/PyLotROLauncher/SettingsWindow.py
@@ -34,12 +34,13 @@
class SettingsWindow:
def __init__(self, parent, hiRes, app, wineProg, wineDebug, patchClient, winePrefix,
- gameDir, homeDir, osType, rootDir):
+ gameDir, homeDir, osType, rootDir, gameClientIdx):
self.homeDir = homeDir
self.osType = osType
self.winSettings = QtGui.QDialog(parent)
+ self.winSettings.setPalette(parent.palette())
uifile = None
@@ -76,6 +77,9 @@ def __init__(self, parent, hiRes, app, wineProg, wineDebug, patchClient, winePre
self.uiSettings.txtGameDir.setText(gameDir)
self.uiSettings.cboGraphics.addItem("Enabled")
self.uiSettings.cboGraphics.addItem("Disabled")
+ self.uiSettings.cboGameClient.addItem("32-bit")
+ self.uiSettings.cboGameClient.addItem("32-bit Legacy (\"Awesomium\")")
+ self.uiSettings.cboGameClient.addItem("64-bit")
self.uiSettings.chkAdvanced.setChecked(False)
self.uiSettings.txtPatchClient.setText(patchClient)
self.uiSettings.txtPatchClient.setEnabled(False)
@@ -101,6 +105,8 @@ def __init__(self, parent, hiRes, app, wineProg, wineDebug, patchClient, winePre
else:
self.uiSettings.cboGraphics.setCurrentIndex(1)
+ self.uiSettings.cboGameClient.setCurrentIndex(int(gameClientIdx))
+
QtCore.QObject.connect(self.uiSettings.btnGameDir, QtCore.SIGNAL("clicked()"), self.btnGameDirClicked)
QtCore.QObject.connect(self.uiSettings.chkAdvanced, QtCore.SIGNAL("clicked()"), self.chkAdvancedClicked)
@@ -202,6 +208,9 @@ def getHiRes(self):
else:
return False
+ def getGameClientIdx(self):
+ return self.uiSettings.cboGameClient.currentIndex()
+
def Run(self):
return self.winSettings.exec_()
diff --git a/PyLotROLauncher/SettingsWizard.py b/PyLotROLauncher/SettingsWizard.py
index da6afff..1ed74be 100644
--- a/PyLotROLauncher/SettingsWizard.py
+++ b/PyLotROLauncher/SettingsWizard.py
@@ -48,6 +48,7 @@ def __init__(self, parent, homeDir, osType, rootDir):
self.gameDir = ""
self.winSettings = QtGui.QDialog(parent)
+ self.winSettings.setPalette(parent.palette())
uifile = None
diff --git a/PyLotROLauncher/StartGame.py b/PyLotROLauncher/StartGame.py
index 1573338..eb339f2 100644
--- a/PyLotROLauncher/StartGame.py
+++ b/PyLotROLauncher/StartGame.py
@@ -34,12 +34,17 @@
class StartGame:
def __init__(self, parent, appName, argTemplate, account, server, ticket,
chatServer, language, runDir, wineProgram, wineDebug, winePrefix,
- hiResEnabled, wineApp, osType, homeDir, icoFileIn, rootDir):
+ hiResEnabled, wineApp, osType, homeDir, icoFileIn, rootDir,
+ crashreceiver, DefaultUploadThrottleMbps, bugurl, authserverurl,
+ supporturl, supportserviceurl, glsticketlifetime, realmName, accountText):
self.winMain = parent
self.homeDir = homeDir
self.winLog = QtGui.QDialog(parent)
+ self.winLog.setPalette(parent.palette())
self.osType = osType
+ self.realmName = realmName
+ self.accountText = accountText
uifile = None
icofile = None
@@ -84,8 +89,12 @@ def __init__(self, parent, appName, argTemplate, account, server, ticket,
self.command = ""
self.arguments = []
- gameParams = argTemplate.replace("{0}", account).replace("{1}", server)\
- .replace("{2}", ticket).replace("{3}", chatServer).replace("{4}", language)
+ gameParams = argTemplate.replace("{SUBSCRIPTION}", account).replace("{LOGIN}", server)\
+ .replace("{GLS}", ticket).replace("{CHAT}", chatServer).replace("{LANG}", language)\
+ .replace("{CRASHRECEIVER}", crashreceiver).replace("{UPLOADTHROTTLE}", DefaultUploadThrottleMbps)\
+ .replace("{BUGURL}", bugurl).replace("{AUTHSERVERURL}", authserverurl)\
+ .replace("{GLSTICKETLIFETIME}", glsticketlifetime).replace("{SUPPORTURL}", supporturl)\
+ .replace("{SUPPORTSERVICEURL}",supportserviceurl)
if not hiResEnabled:
gameParams = gameParams + " --HighResOutOfDate"
@@ -172,6 +181,11 @@ def __init__(self, parent, appName, argTemplate, account, server, ticket,
for arg in tempArg.split(" "):
self.arguments.append(arg)
+ self.uiLog.txtLog.append("Connecting to server: " + realmName)
+ self.uiLog.txtLog.append("Account: " + accountText)
+ self.uiLog.txtLog.append("Game Directory: " + runDir)
+ self.uiLog.txtLog.append("Game Client: " + appName)
+
def readOutput(self):
self.uiLog.txtLog.append(QByteArray2str(self.process.readAllStandardOutput()))
diff --git a/PyLotROLauncher/certificates/README b/PyLotROLauncher/certificates/README
new file mode 100644
index 0000000..d8f04d4
--- /dev/null
+++ b/PyLotROLauncher/certificates/README
@@ -0,0 +1,33 @@
+In order to connect via SSL/TLS, the server's certificate is validated against
+the certificate chain stored in this file. When Turbine updates their
+certificate chain, this program will break (again) with the error message:
+
+ [E15] SSL Error occured in HTTPS connection
+
+In that case you will need re-assemble the certificate chain and place it into
+this file. Useful commands at the time of this writing include:
+
+ openssl s_client -connect gls.lotro.com:443
+
+...which will attempt to connect to the LotRO authentication server and
+allow you to copy+paste the server's certificate and begin hunting down the
+chain. In order to read each certificate as you work your way up the chain,
+you can use:
+
+ openssl x509 -in
-text
+
+...in order to dump information about the specified certificate. You may
+need to add '-inform der' if the certificate is in binary format. Look
+for the 'Authority Information Access' under 'X509v3 extensions' in order
+to quickly retrieve URLs for the certificate chain. You may also need to
+retrieve the root certificate from your local '/etc/ssl/certs/'.
+
+When you have retrieved all of the certificates, you will need to concatenate
+them together. In order to verify that this has been done correctly, again use
+the 'openssl verify' command, and in addition use the '-CAfile '
+argument. It's best to start with the root authority and then work your way
+down (in the order opposite of which the certificates were retrieved). Note
+that, when I did this, the root authority wasn't required for the command
+to verify, but was necessary for the program to actually work.
+
+Good luck.
diff --git a/PyLotROLauncher/certificates/ca_certs.pem b/PyLotROLauncher/certificates/ca_certs.pem
index 85e7722..d5ec2dc 100644
--- a/PyLotROLauncher/certificates/ca_certs.pem
+++ b/PyLotROLauncher/certificates/ca_certs.pem
@@ -1,53 +1,90 @@
------BEGIN CERTIFICATE-----
-MIIEpjCCA46gAwIBAgIQEOd26KZabjd+BQMG1Dwl6jANBgkqhkiG9w0BAQUFADCB
-lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
-Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
-dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
-SGFyZHdhcmUwHhcNMDYwNDEwMDAwMDAwWhcNMjAwNTMwMTA0ODM4WjBiMQswCQYD
-VQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYD
-VQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEi
-MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDD3TbMg8MYVbCW2RMl0yaGSDi7
-Fn/xnyn2/QPx7U0mmlbwtRoazebMhVVApLXQDcoi7z0jxn5szLyh6XxQRuC9FK1l
-EsILEWlSCgeSH3NvwbrXYvDOAC40pcjmLw/sDepEYXVo5eTcgDZP2nhdUyWUlPVP
-Ljpgbwym2bP2Ki4DEtUmQgdRsmRXcdwhHInHaaPm+8J7bu8Mh/tQZOhOS+/ncZuD
-Y2HJMo2M7BSn5ImtPysmZOSFQvKJUOE6vhXjRSXiWsuMP+AzHjUJWoTqfl2h9ZGA
-CigGt8sxQSVhiwHpVqL2Pl8v88RD9hmUdYNMoYJCOsa6xAkwpuF1AlG5XmSLAgMB
-AAGjggEgMIIBHDAfBgNVHSMEGDAWgBShcl8mGyiYQ5VdBzfVhZadS9LDRTAdBgNV
-HQ4EFgQUPEHijwgIqUwliY1txTjQ/IWMYhcwDgYDVR0PAQH/BAQDAgEGMBIGA1Ud
-EwEB/wQIMAYBAf8CAQAwGQYDVR0gBBIwEDAOBgwrBgEEAYYOAQIBAwEwRAYDVR0f
-BD0wOzA5oDegNYYzaHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmly
-c3QtSGFyZHdhcmUuY3JsMFUGCCsGAQUFBwEBBEkwRzBFBggrBgEFBQcwAoY5aHR0
-cDovL3d3dy51c2VydHJ1c3QuY29tL2NhY2VydHMvVVROQWRkVHJ1c3RTZXJ2ZXJf
-Q0EuY3J0MA0GCSqGSIb3DQEBBQUAA4IBAQBoq/zvgGsYsrCzo0WJy1PFouavCKn9
-/w9JrP/kn9dBfKPFouiq4FchLcOqfAxMKAt59O5MMq15Dn6iXjQYT99U8b1ofOPT
-10ZebWTC922IgnMM75mF6qnvMkrwg59zkQykPisxUaZijxWE+aY6EjA/2m74zMcZ
-kg9c9P4X8ZUIR1IsUI/om6XurnAziZGC/jCqdnZZ12wY0ysSWx0oHXhx9s02oukH
-SEQ751duggqtxYrd6FO0ca8T0gadN21TP4o1CPr+ohbmuW9cVjnWxqrvGWfOE8W4
-lQX7CkTJn6lAJUsyEa8H/gjVQnHp4VOLFR/dKgeVcCRvZF7Tt5AuiyHY
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB
-lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
-Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
-dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
-SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG
-A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe
-MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v
-d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh
-cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn
-0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ
-M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a
-MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd
-oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI
-DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy
-oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD
-VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0
-dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy
-bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF
-BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
-//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli
-CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE
-CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t
-3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS
-KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA==
------END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
+QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
+MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
+b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
+CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
+nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
+43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
+T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
+gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
+BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
+TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
+DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
+hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
+06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
+PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
+YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
+CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIE6jCCA9KgAwIBAgIQCjUI1VwpKwF9+K1lwA/35DANBgkqhkiG9w0BAQsFADBh
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
+QTAeFw0yMDA5MjQwMDAwMDBaFw0zMDA5MjMyMzU5NTlaME8xCzAJBgNVBAYTAlVT
+MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxKTAnBgNVBAMTIERpZ2lDZXJ0IFRMUyBS
+U0EgU0hBMjU2IDIwMjAgQ0ExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAwUuzZUdwvN1PWNvsnO3DZuUfMRNUrUpmRh8sCuxkB+Uu3Ny5CiDt3+PE0J6a
+qXodgojlEVbbHp9YwlHnLDQNLtKS4VbL8Xlfs7uHyiUDe5pSQWYQYE9XE0nw6Ddn
+g9/n00tnTCJRpt8OmRDtV1F0JuJ9x8piLhMbfyOIJVNvwTRYAIuE//i+p1hJInuW
+raKImxW8oHzf6VGo1bDtN+I2tIJLYrVJmuzHZ9bjPvXj1hJeRPG/cUJ9WIQDgLGB
+Afr5yjK7tI4nhyfFK3TUqNaX3sNk+crOU6JWvHgXjkkDKa77SU+kFbnO8lwZV21r
+eacroicgE7XQPUDTITAHk+qZ9QIDAQABo4IBrjCCAaowHQYDVR0OBBYEFLdrouqo
+qoSMeeq02g+YssWVdrn0MB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFV
+MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
+EgYDVR0TAQH/BAgwBgEB/wIBADB2BggrBgEFBQcBAQRqMGgwJAYIKwYBBQUHMAGG
+GGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBABggrBgEFBQcwAoY0aHR0cDovL2Nh
+Y2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNydDB7BgNV
+HR8EdDByMDegNaAzhjFodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRH
+bG9iYWxSb290Q0EuY3JsMDegNaAzhjFodHRwOi8vY3JsNC5kaWdpY2VydC5jb20v
+RGlnaUNlcnRHbG9iYWxSb290Q0EuY3JsMDAGA1UdIAQpMCcwBwYFZ4EMAQEwCAYG
+Z4EMAQIBMAgGBmeBDAECAjAIBgZngQwBAgMwDQYJKoZIhvcNAQELBQADggEBAHer
+t3onPa679n/gWlbJhKrKW3EX3SJH/E6f7tDBpATho+vFScH90cnfjK+URSxGKqNj
+OSD5nkoklEHIqdninFQFBstcHL4AGw+oWv8Zu2XHFq8hVt1hBcnpj5h232sb0HIM
+ULkwKXq/YFkQZhM6LawVEWwtIwwCPgU7/uWhnOKK24fXSuhe50gG66sSmvKvhMNb
+g0qZgYOrAKHKCjxMoiWJKiKnpPMzTFuMLhoClw+dj20tlQj7T9rxkTgl4ZxuYRiH
+as6xuwAwapu3r9rxxZf+ingkquqTgLozZXq8oXfpf2kUCwA/d5KxTVtzhwoT0JzI
+8ks5T1KESaZMkE4f97Q=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIGwDCCBaigAwIBAgIQDuAmwkWKDUFDxKxfPW7GOjANBgkqhkiG9w0BAQsFADBP
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMSkwJwYDVQQDEyBE
+aWdpQ2VydCBUTFMgUlNBIFNIQTI1NiAyMDIwIENBMTAeFw0yMTA0MTMwMDAwMDBa
+Fw0yMjA0MjgyMzU5NTlaMHAxCzAJBgNVBAYTAlVTMRYwFAYDVQQIEw1NYXNzYWNo
+dXNldHRzMRAwDgYDVQQHEwdOZWVkaGFtMSEwHwYDVQQKExhTdGFuZGluZyBTdG9u
+ZSBHYW1lcyBMTEMxFDASBgNVBAMMCyoubG90cm8uY29tMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAztIfPfYhzT2nevQqOrtm8M4NF5j5FWG7UkZm7ab0
+BfzPcqdV+EaoJntDP30/QpvoLryACDBJ+iO2g+EWISaK0uWaW2agCOiYjTcZFOoQ
+ecRqQFNrRZKDZ/kFU5qqyV3ex4DHc0mBmssuaale4IFqj/NcApAt/xaSLzyfXerU
+J9zgJYLbphIpZcUB/7YofhOc2dgzqgSoPA0N31SUvyZQWJJu3F1q4YPa8ApZ+5OG
+xNbruwzjwZs8NUbiP2v2HqjxkpYdU5CjYFB8JeF8nGa3aM7xTLf2NxdGBPp2zr0h
+ybmGeoJNL6FtV0ieMzQiH+VY8hhw0QT8xTdUDCpzalnitQIDAQABo4IDdTCCA3Ew
+HwYDVR0jBBgwFoAUt2ui6qiqhIx56rTaD5iyxZV2ufQwHQYDVR0OBBYEFK5HJlnj
+BHYloLJvDYjGYAb1sd0LMCEGA1UdEQQaMBiCCyoubG90cm8uY29tgglsb3Ryby5j
+b20wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD
+AjCBiwYDVR0fBIGDMIGAMD6gPKA6hjhodHRwOi8vY3JsMy5kaWdpY2VydC5jb20v
+RGlnaUNlcnRUTFNSU0FTSEEyNTYyMDIwQ0ExLmNybDA+oDygOoY4aHR0cDovL2Ny
+bDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VExTUlNBU0hBMjU2MjAyMENBMS5jcmww
+PgYDVR0gBDcwNTAzBgZngQwBAgIwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5k
+aWdpY2VydC5jb20vQ1BTMH0GCCsGAQUFBwEBBHEwbzAkBggrBgEFBQcwAYYYaHR0
+cDovL29jc3AuZGlnaWNlcnQuY29tMEcGCCsGAQUFBzAChjtodHRwOi8vY2FjZXJ0
+cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUTFNSU0FTSEEyNTYyMDIwQ0ExLmNydDAM
+BgNVHRMBAf8EAjAAMIIBgAYKKwYBBAHWeQIEAgSCAXAEggFsAWoAdgApeb7wnjk5
+IfBWc59jpXflvld9nGAK+PlNXSZcJV3HhAAAAXjIzphwAAAEAwBHMEUCIFznUqt4
+r3oqLf0EJCxckG8w65dl9TtIqWYlJRBNsEyqAiEAqei2Ma1amnDqPEgub2+AbiKa
+HRByKwNyQHAlJIKZ0SUAdwAiRUUHWVUkVpY/oS/x922G4CMmY63AS39dxoNcbuIP
+AgAAAXjIzpjQAAAEAwBIMEYCIQCJmFsghrbvklCc8uTa3PNQ3/oXFCbZ9M52ynCj
+yNjrLQIhAJ9/iL3H/Vp3I7vXfvjY76g5holbnikmBxZHzGFrhScbAHcAQcjKsd8i
+RkoQxqE6CUKHXk4xixsD6+tLx2jwkGKWBvYAAAF4yM6YbAAABAMASDBGAiEArRTv
+870dWCMuGYddzSbZv3sy0f7ZBuNENtaN1VFjlIICIQDtKbotdQgKgrbkjOnAgyPp
+R7SZ4nAtl3KkKRvFBjR8sDANBgkqhkiG9w0BAQsFAAOCAQEATpQsD909GlE+R72y
+e/ZiIDZLpV2hEXmVXoMwiTbGieh3aoQTXCY7kNMVJ36hCtflOEbREaKcjsF5mhDs
+kXAtttg3eLrP092Nof5dfVkNKZx6dNs0tuU0jT/1hr7J2j1Q4DhoLepzH8FK40pz
+/05+H/1nfrSgAEEbP6kXpKk6rjY7fBsouESgA2ht+jk3opPUoZeZRvavL9CnKYQM
+DUIhYcPx3F8EgQRL0uHDgXTyswXrEtJdFY2X5vSFzF5/MxSnW+XqeYRjfuuS437c
+TRNMvO/B7/IzA1/mQNbO1KBDyruP6sr8VK5L8n+kap8WJuVBKX5I1F6CodaIjS2m
+/uP+YA==
+-----END CERTIFICATE-----
diff --git a/PyLotROLauncher/ui/winSettings.ui b/PyLotROLauncher/ui/winSettings.ui
index 6e6927f..cf5e14e 100644
--- a/PyLotROLauncher/ui/winSettings.ui
+++ b/PyLotROLauncher/ui/winSettings.ui
@@ -1,47 +1,48 @@
-
+
+
dlgSettings
-
-
+
+
Qt::ApplicationModal
-
+
0
0
460
- 338
+ 379
-
+
Verdana
12
-
+
Game Settings
-
+
true
-
-
+
+
- 5
- 301
+ 0
+ 340
450
32
-
+
Qt::Horizontal
-
+
QDialogButtonBox::Cancel|QDialogButtonBox::Save
-
-
+
+
5
10
@@ -49,12 +50,12 @@
23
-
+
Application
-
-
+
+
155
5
@@ -63,8 +64,8 @@
-
-
+
+
5
47
@@ -72,12 +73,12 @@
23
-
+
WINEDEBUG
-
-
+
+
155
43
@@ -86,8 +87,8 @@
-
-
+
+
5
85
@@ -95,12 +96,12 @@
23
-
+
WINEPREFIX
-
-
+
+
155
80
@@ -109,11 +110,11 @@
-
-
+
+
true
-
+
155
79
@@ -122,8 +123,8 @@
-
-
+
+
155
117
@@ -132,8 +133,8 @@
-
-
+
+
419
117
@@ -141,12 +142,12 @@
30
-
+
...
-
-
+
+
5
121
@@ -154,12 +155,12 @@
23
-
+
Game Directory
-
-
+
+
5
158
@@ -167,12 +168,12 @@
23
-
+
Hi-Res Graphics
-
-
+
+
155
153
@@ -181,68 +182,91 @@
-
-
+
+
- 5
- 196
+ 0
+ 237
280
28
-
+
Advanced Options
-
+
false
-
-
+
+
- 155
- 229
+ 150
+ 270
300
31
-
-
+
+
- 5
- 233
+ 0
+ 274
140
23
-
+
Wine Program
-
-
+
+
- 155
- 265
+ 150
+ 306
300
31
-
-
+
+
- 5
- 269
+ 0
+ 310
150
23
-
+
Patch Client DLL
+
+
+
+ 155
+ 193
+ 300
+ 33
+
+
+
+
+
+
+ 5
+ 197
+ 150
+ 23
+
+
+
+ Game Client
+
+
@@ -252,11 +276,11 @@
dlgSettings
accept()
-
+
248
254
-
+
157
274
@@ -268,11 +292,11 @@
dlgSettings
reject()
-
+
316
260
-
+
286
274
diff --git a/PyLotROLauncher/ui/winSettingsNative.ui b/PyLotROLauncher/ui/winSettingsNative.ui
index d5fd1df..cf8aded 100644
--- a/PyLotROLauncher/ui/winSettingsNative.ui
+++ b/PyLotROLauncher/ui/winSettingsNative.ui
@@ -1,47 +1,48 @@
-
+
+
dlgSettings
-
-
+
+
Qt::ApplicationModal
-
+
0
0
460
- 190
+ 236
-
+
Verdana
12
-
+
Game Settings
-
+
true
-
-
+
+
5
- 150
+ 192
450
32
-
+
Qt::Horizontal
-
+
QDialogButtonBox::Cancel|QDialogButtonBox::Save
-
-
+
+
155
6
@@ -50,8 +51,8 @@
-
-
+
+
419
6
@@ -59,12 +60,12 @@
30
-
+
...
-
-
+
+
5
10
@@ -72,12 +73,12 @@
23
-
+
Game Directory
-
-
+
+
5
47
@@ -85,12 +86,12 @@
23
-
+
Hi-Res Graphics
-
-
+
+
155
42
@@ -99,45 +100,68 @@
-
-
+
+
5
- 80
+ 122
280
28
-
+
Advanced Options
-
+
false
-
-
+
+
155
- 113
+ 155
300
31
-
-
+
+
5
- 117
+ 159
150
23
-
+
Patch Client DLL
+
+
+
+ 5
+ 85
+ 150
+ 23
+
+
+
+ Game Client
+
+
+
+
+
+ 155
+ 81
+ 300
+ 33
+
+
+
@@ -147,11 +171,11 @@
dlgSettings
accept()
-
+
248
254
-
+
157
274
@@ -163,11 +187,11 @@
dlgSettings
reject()
-
+
316
260
-
+
286
274
diff --git a/README b/README
index 7c96c65..414ad8b 100644
--- a/README
+++ b/README
@@ -57,7 +57,7 @@ find relevant installations of LotRO or DDO.
For CrossOver and CrossOver Games it searches
in the default bottle location. For Wine it
looks for wine folders in your home directory
-(folders tarting with a full stop with a
+(folders starting with a full stop with a
directory called drive_c under that). For all
options it tries to find the game in the
"Program Files" directory (or directories off