Compare commits

...

32 Commits

Author SHA1 Message Date
grossmj
37faa39309 Release v2.2.2 2019-11-04 18:33:29 +08:00
grossmj
4d64598ed2 Fix KeyError: 'spice+agent'. Fixes #2890 2019-11-03 15:19:18 +08:00
grossmj
5132c4e172 Fix wrong log.error() call when exporting file. 2019-11-02 23:19:04 +08:00
grossmj
3c3fdd9ffd Revert "Explicitly cleanup the cache directory."
This reverts commit 8095fef228.
2019-11-02 15:47:24 +08:00
grossmj
efa50571c6 Fix "UnboundLocalError: local variable 'pywintypes' referenced before assignment" 2019-11-02 15:45:16 +08:00
grossmj
ca9b10fcca Fix version string. 2019-11-02 15:27:28 +08:00
grossmj
8660161b10 Fix GUI uses only telnet console. Fixes #2885 2019-11-02 02:23:13 +08:00
grossmj
50ebfb9c06 Fix missing sys module in sudo.py Fixes #2886 2019-11-02 02:06:33 +08:00
grossmj
26df59d6b6 Development on 2.2.2dev1 2019-11-01 18:43:36 +08:00
grossmj
b903e2ad73 Release v2.2.1 2019-11-01 17:53:20 +08:00
grossmj
b2fe7eb643 Check if console_type is None. 2019-11-01 17:47:26 +08:00
grossmj
8095fef228 Explicitly cleanup the cache directory. 2019-11-01 17:46:53 +08:00
grossmj
b8da5440f5 Get Windows interface from registry if cannot load win32com module. 2019-11-01 17:44:47 +08:00
grossmj
6cea094e4e Ignore OSError returned by psutil when bringing console to front. 2019-11-01 17:44:06 +08:00
grossmj
9ac46c9d50 Catch error if NPF or NPCAP service cannot be detected. Ref https://github.com/GNS3/gns3-server/issues/1670 2019-10-30 17:59:19 +08:00
grossmj
6dc44d5108 Better handling for reading synchronous JSON response from server. Ref #2874 2019-10-17 12:45:40 +08:00
grossmj
9c6be0341b Fix tests. 2019-10-17 12:34:34 +08:00
grossmj
011a49e998 Fix JSONDecodeError when getting server version. Fixes #2874 2019-10-17 12:31:15 +08:00
grossmj
e18c2df5f5 Fix FileNotFoundError exceptions when launching SPICE or VNC clients. 2019-10-17 12:19:55 +08:00
grossmj
1794b8389f Fix UnboundLocalError local variable 'win32serviceutil' referenced before assignment 2019-10-17 12:12:46 +08:00
grossmj
0379c370eb Merge remote-tracking branch 'remotes/origin/master' into 2.2 2019-10-15 23:36:49 +08:00
Jeremy Grossmann
e03550a89b Merge pull request #2872 from fatoms/Tab_Order
Tab Order in Preferences and Project Dialog
2019-10-15 22:35:53 +07:00
Dominic
c6ea775e81 'Fix' tab order in preferences dialog so it follows the layout 2019-10-12 22:06:30 +02:00
Dominic
38233ba5e9 'Fix' tab order in edit project dialog so it follows the layout 2019-10-12 22:05:52 +02:00
grossmj
89c1272bc1 Use compatible shlex_quote to handle case where Windows needs double quotes around file names, not single quotes. Ref https://github.com/GNS3/gns3-gui/issues/2866 2019-10-09 17:02:30 +08:00
grossmj
8bbb46c599 Use 0.0.0.0 by default for server host. Fixes https://github.com/GNS3/gns3-server/issues/1663 2019-10-09 16:35:42 +08:00
grossmj
74fca3d736 Set default host to "localhost". Fixes https://github.com/GNS3/gns3-server/issues/1663 2019-10-08 18:28:11 +08:00
grossmj
7aeed7aa59 Catch IndexError when configuring port names. Fixes #2865 2019-10-08 16:15:36 +08:00
grossmj
aa15ace887 Bump version to 2.2.1dev1 2019-10-08 16:05:37 +08:00
grossmj
2d0a7b5f58 Release v2.2.0 2019-09-30 16:24:26 +08:00
grossmj
20a09b56c1 Merge branch 'master' into 2.2
# Conflicts:
#	gns3/version.py
2019-09-24 14:07:38 +08:00
grossmj
1938cdabae Bump version to 2.2.0dev18 2019-09-24 14:02:36 +08:00
28 changed files with 292 additions and 89 deletions

View File

@@ -1,5 +1,35 @@
# Change Log
## 2.2.2 04/11/2019
* Fix KeyError: 'spice+agent'. Fixes #2890
* Fix wrong log.error() call when exporting file.
* Revert "Explicitly cleanup the cache directory."
* Fix "UnboundLocalError: local variable 'pywintypes' referenced before assignment"
* Fix GUI uses only telnet console. Fixes #2885
* Fix missing sys module in sudo.py Fixes #2886
## 2.2.1 01/11/2019
* Check if console_type is None.
* Explicitly cleanup the cache directory.
* Get Windows interface from registry if cannot load win32com module.
* Ignore OSError returned by psutil when bringing console to front.
* Catch error if NPF or NPCAP service cannot be detected. Ref https://github.com/GNS3/gns3-server/issues/1670
* Better handling for reading synchronous JSON response from server. Ref #2874
* Fix JSONDecodeError when getting server version. Fixes #2874
* Fix FileNotFoundError exceptions when launching SPICE or VNC clients.
* Fix UnboundLocalError local variable 'win32serviceutil' referenced before assignment
* 'Fix' tab order in preferences dialog so it follows the layout
* 'Fix' tab order in edit project dialog so it follows the layout
* Use compatible shlex_quote to handle case where Windows needs double quotes around file names, not single quotes. Ref https://github.com/GNS3/gns3-gui/issues/2866
* Use 0.0.0.0 by default for server host. Fixes https://github.com/GNS3/gns3-server/issues/1663
* Catch IndexError when configuring port names. Fixes #2865
## 2.2.0 30/09/2019
* No changes
## 2.2.0rc5 09/09/2019
* Adjust size for setup dialog and remove question about running the wizard again. Ref #2846

View File

@@ -52,7 +52,7 @@ class CrashReport:
Report crash to a third party service
"""
DSN = "https://cef6948387d14919929d7e3db6b11835:064728e23bf043f99100cf271bcd5547@sentry.io/38506"
DSN = "https://dbedb95015d948b3b38917d7ac01e15b:1fcb50016b474c12b14c53d2b83eeabc@sentry.io/38506"
if hasattr(sys, "frozen"):
cacert = get_resource("cacert.pem")
if cacert is not None and os.path.isfile(cacert):

View File

@@ -44,6 +44,9 @@ class ConsoleCommandDialog(QtWidgets.QDialog, Ui_uiConsoleCommandDialog):
"""
super().__init__(parent)
self.setupUi(self)
if console_type == "spice+agent":
# special case for spice+agent, use the spice console type
console_type = "spice"
self._console_type = console_type
self._current = current
@@ -63,7 +66,7 @@ class ConsoleCommandDialog(QtWidgets.QDialog, Ui_uiConsoleCommandDialog):
elif self._console_type == "vnc":
self._consoles = copy.copy(PRECONFIGURED_VNC_CONSOLE_COMMANDS)
self._consoles.update(self._settings[self._console_type])
elif self._console_type.startswith("spice"):
elif self._console_type == "spice":
self._consoles = copy.copy(PRECONFIGURED_SPICE_CONSOLE_COMMANDS)
self._consoles.update(self._settings[self._console_type])
@@ -121,8 +124,8 @@ class ConsoleCommandDialog(QtWidgets.QDialog, Ui_uiConsoleCommandDialog):
dialog = ConsoleCommandDialog(parent, console_type=console_type, current=current)
dialog.show()
if dialog.exec_():
return (True, dialog.uiCommandPlainTextEdit.toPlainText().replace("\n", " "))
return (False, None)
return True, dialog.uiCommandPlainTextEdit.toPlainText().replace("\n", " ")
return False, None
if __name__ == '__main__':

View File

@@ -1054,8 +1054,7 @@ class GraphicsView(QtWidgets.QGraphicsView):
# TightVNC has lack support of IPv6 host at this moment
if "vncviewer" in node.consoleCommand() and ":" in node.consoleHost():
QtWidgets.QMessageBox.warning(
self, "TightVNC", "TightVNC (vncviewer) may not start because of lack of IPv6 support.")
QtWidgets.QMessageBox.warning(self, "TightVNC", "TightVNC (vncviewer) may not start because of lack of IPv6 support.")
try:
node.openConsole(aux=aux)
@@ -1116,24 +1115,20 @@ class GraphicsView(QtWidgets.QGraphicsView):
Allow user to use a custom console for this VM
"""
current_cmd = None
console_type = "telnet"
for item in self.scene().selectedItems():
if isinstance(item, NodeItem) and item.node().console() is not None and item.node().initialized() and item.node().status() == Node.started:
if isinstance(item, NodeItem) and item.node().console() is not None and item.node().initialized():
if item.node().consoleType() not in ("telnet", "serial", "vnc", "spice", "spice+agent"):
continue
current_cmd = item.node().consoleCommand()
console_type = item.node().consoleType()
(ok, cmd) = ConsoleCommandDialog.getCommand(self, console_type=console_type, current=current_cmd)
if ok:
for item in self.scene().selectedItems():
if isinstance(item, NodeItem) and item.node().console() is not None and item.node().initialized() and item.node().status() == Node.started:
node = item.node()
if node.consoleType() not in ("telnet", "serial", "vnc", "spice", "spice+agent"):
continue
(ok, cmd) = ConsoleCommandDialog.getCommand(self, console_type=console_type, current=current_cmd)
if ok:
try:
node.openConsole(command=cmd)
if item.node().status() != Node.started:
QtWidgets.QMessageBox.warning(self, "Console", "This node must be started before a console can be opened")
continue
item.node().openConsole(command=cmd)
except (OSError, ValueError) as e:
QtWidgets.QMessageBox.critical(self, "Console", "Cannot start console application: {}".format(e))

View File

@@ -764,18 +764,17 @@ class HTTPClient(QtCore.QObject):
status = response.attribute(QtNetwork.QNetworkRequest.HttpStatusCodeAttribute)
if response.error() != QtNetwork.QNetworkReply.NoError:
log.debug("Error while connecting to local server {}".format(response.errorString()))
return status, None
else:
content_type = response.header(QtNetwork.QNetworkRequest.ContentTypeHeader)
if status == 200:
if content_type == "application/json":
content = bytes(response.readAll())
if status == 200 and content_type == "application/json":
content = bytes(response.readAll())
try:
json_data = json.loads(content.decode("utf-8"))
except (UnicodeEncodeError, ValueError) as e:
log.warning("Could not read JSON data returned from {}: {}".format(url, e))
else:
return status, json_data
else:
return status, None
return 0, None
return status, None
@classmethod
def fromUrl(cls, url, network_manager=None, base_settings=None):

View File

@@ -130,6 +130,7 @@ class LocalServer(QtCore.QObject):
import win32serviceutil
except ImportError as e:
log.error("Could not check if the {} service is running: {}".format(service_name, e))
return
try:
if win32serviceutil.QueryServiceStatus(service_name, None)[1] != win32service.SERVICE_RUNNING:
@@ -368,9 +369,13 @@ class LocalServer(QtCore.QObject):
self._checkUbridgePermissions()
if sys.platform.startswith('win'):
if not self._checkWindowsService("npf") and not self._checkWindowsService("npcap"):
log.warning("The NPF or NPCAP service is not installed, please install Winpcap or Npcap and reboot.")
if sys.platform.startswith("win"):
import pywintypes
try:
if not self._checkWindowsService("npf") and not self._checkWindowsService("npcap"):
log.warning("The NPF or NPCAP service is not installed, please install Winpcap or Npcap and reboot.")
except pywintypes.error as e:
log.warning("Could not check if the NPF or Npcap service is running: {}".format(e.strerror))
self._port = self._settings["port"]
# check the local server path

View File

@@ -391,7 +391,7 @@ class QemuVMConfigurationPage(QtWidgets.QWidget, Ui_QemuVMConfigPageWidget):
try:
ports = StandardPortNameFactory(adapters, first_port_name, port_name_format, port_segment_size)
except (ValueError, KeyError):
except (IndexError, ValueError, KeyError):
QtWidgets.QMessageBox.critical(self, "Invalid format", "Invalid port name format")
return

View File

@@ -99,7 +99,7 @@ class VirtualBoxVMConfigurationPage(QtWidgets.QWidget, Ui_virtualBoxVMConfigPage
try:
ports = StandardPortNameFactory(adapters, first_port_name, port_name_format, port_segment_size)
except (ValueError, KeyError):
except (IndexError, ValueError, KeyError):
QtWidgets.QMessageBox.critical(self, "Invalid format", "Invalid port name format")
return

View File

@@ -99,7 +99,7 @@ class VMwareVMConfigurationPage(QtWidgets.QWidget, Ui_VMwareVMConfigPageWidget):
try:
ports = StandardPortNameFactory(adapters, first_port_name, port_name_format, port_segment_size)
except (ValueError, KeyError):
except (IndexError, ValueError, KeyError):
QtWidgets.QMessageBox.critical(self, "Invalid format", "Invalid port name format")
return

View File

@@ -628,12 +628,12 @@ class Node(BaseNode):
from .main_window import MainWindow
general_settings = MainWindow.instance().settings()
if console_type != "telnet":
if not console_type:
console_type = self.consoleType()
if console_type == "vnc":
return general_settings["vnc_console_command"]
if console_type.startswith("spice"):
return general_settings["spice_console_command"]
if console_type == "vnc":
return general_settings["vnc_console_command"]
elif console_type.startswith("spice"):
return general_settings["spice_console_command"]
return general_settings["telnet_console_command"]
def consoleType(self):
@@ -765,7 +765,7 @@ class Node(BaseNode):
with open(context["path"], "wb+") as f:
f.write(raw_body)
except OSError as e:
log.erro("Can't write %s: %s", context["path"], str(e))
log.error("Cannot export file '{}': {}".format(context["path"], e))
def exportConfigsToDirectory(self, directory):
"""

View File

@@ -330,7 +330,7 @@ GRAPHICS_VIEW_SETTINGS = {
LOCAL_SERVER_SETTINGS = {
"path": "gns3server",
"ubridge_path": "ubridge",
"host": None,
"host": "0.0.0.0",
"port": DEFAULT_LOCAL_SERVER_PORT,
"images_path": DEFAULT_IMAGES_PATH,
"projects_path": DEFAULT_PROJECTS_PATH,

View File

@@ -38,7 +38,7 @@ def spiceConsole(host, port, command):
"""
if len(command.strip(' ')) == 0:
log.warning('SPICE client is not configured')
log.error("SPICE client is not configured")
return
# ipv6 support
@@ -50,7 +50,7 @@ def spiceConsole(host, port, command):
command = command.replace("%p", str(port))
try:
log.info('starting SPICE program "{}"'.format(command))
log.debug('starting SPICE program "{}"'.format(command))
if sys.platform.startswith("win"):
# use the string on Windows
subprocess.Popen(command)
@@ -59,5 +59,4 @@ def spiceConsole(host, port, command):
args = shlex.split(command)
subprocess.Popen(args, env=os.environ)
except (OSError, ValueError, subprocess.SubprocessError) as e:
log.warning('could not start SPICE program "{}": {}'.format(command, e))
raise
log.error("Could not start SPICE program with command '{}': {}".format(command, e))

View File

@@ -179,6 +179,17 @@
</item>
</layout>
</widget>
<tabstops>
<tabstop>tabWidget</tabstop>
<tabstop>uiProjectNameLineEdit</tabstop>
<tabstop>uiSceneWidthSpinBox</tabstop>
<tabstop>uiSceneHeightSpinBox</tabstop>
<tabstop>uiNodeGridSizeSpinBox</tabstop>
<tabstop>uiDrawingGridSizeSpinBox</tabstop>
<tabstop>uiProjectAutoOpenCheckBox</tabstop>
<tabstop>uiProjectAutoStartCheckBox</tabstop>
<tabstop>uiProjectAutoCloseCheckBox</tabstop>
</tabstops>
<resources/>
<connections>
<connection>

View File

@@ -223,7 +223,16 @@
<string>Binary images</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_7">
<property name="margin">
<property name="leftMargin">
<number>10</number>
</property>
<property name="topMargin">
<number>10</number>
</property>
<property name="rightMargin">
<number>10</number>
</property>
<property name="bottomMargin">
<number>10</number>
</property>
<item>
@@ -275,6 +284,9 @@
</item>
<item>
<widget class="QListWidget" name="uiImageDirectoriesListWidget">
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
@@ -370,7 +382,16 @@
<string>Console applications</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="margin">
<property name="leftMargin">
<number>10</number>
</property>
<property name="topMargin">
<number>10</number>
</property>
<property name="rightMargin">
<number>10</number>
</property>
<property name="bottomMargin">
<number>10</number>
</property>
<item>
@@ -481,7 +502,16 @@
<string>VNC</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_6">
<property name="margin">
<property name="leftMargin">
<number>10</number>
</property>
<property name="topMargin">
<number>10</number>
</property>
<property name="rightMargin">
<number>10</number>
</property>
<property name="bottomMargin">
<number>10</number>
</property>
<item>
@@ -684,6 +714,9 @@
<height>50</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
@@ -730,16 +763,6 @@
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="uiDrawLinkStatusPointsCheckBox">
<property name="text">
<string>Draw link status points</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="12" column="0" colspan="3">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
@@ -785,6 +808,9 @@
<height>50</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
@@ -801,6 +827,9 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="suffix">
<string> pixels</string>
</property>
@@ -826,6 +855,9 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="suffix">
<string> pixels</string>
</property>
@@ -879,6 +911,9 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="minimum">
<number>5</number>
</property>
@@ -901,6 +936,9 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="minimum">
<number>5</number>
</property>
@@ -945,6 +983,16 @@
</property>
</spacer>
</item>
<item row="5" column="0" colspan="2">
<widget class="QCheckBox" name="uiDrawLinkStatusPointsCheckBox">
<property name="text">
<string>Draw link status points</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="uiMiscTab">
@@ -952,7 +1000,16 @@
<string>Miscellaneous</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="margin">
<property name="leftMargin">
<number>10</number>
</property>
<property name="topMargin">
<number>10</number>
</property>
<property name="rightMargin">
<number>10</number>
</property>
<property name="bottomMargin">
<number>10</number>
</property>
<item>
@@ -1066,6 +1123,56 @@
</item>
</layout>
</widget>
<tabstops>
<tabstop>uiProjectsPathLineEdit</tabstop>
<tabstop>uiProjectsPathToolButton</tabstop>
<tabstop>uiSymbolsPathLineEdit</tabstop>
<tabstop>uiSymbolsPathToolButton</tabstop>
<tabstop>uiConfigsPathLineEdit</tabstop>
<tabstop>uiConfigsPathToolButton</tabstop>
<tabstop>uiAppliancesPathLineEdit</tabstop>
<tabstop>uiAppliancesPathToolButton</tabstop>
<tabstop>uiStyleComboBox</tabstop>
<tabstop>uiSymbolThemeComboBox</tabstop>
<tabstop>uiImportConfigurationFilePushButton</tabstop>
<tabstop>uiExportConfigurationFilePushButton</tabstop>
<tabstop>uiBrowseConfigurationPushButton</tabstop>
<tabstop>uiImagesPathLineEdit</tabstop>
<tabstop>uiImagesPathToolButton</tabstop>
<tabstop>uiImageDirectoriesAddPushButton</tabstop>
<tabstop>uiImageDirectoriesDeletePushButton</tabstop>
<tabstop>uiTelnetConsoleCommandLineEdit</tabstop>
<tabstop>uiTelnetConsolePreconfiguredCommandPushButton</tabstop>
<tabstop>uiDelayConsoleAllSpinBox</tabstop>
<tabstop>uiVNCConsoleCommandLineEdit</tabstop>
<tabstop>uiVNCConsolePreconfiguredCommandPushButton</tabstop>
<tabstop>uiSPICEConsoleCommandLineEdit</tabstop>
<tabstop>uiSPICEConsolePreconfiguredCommandPushButton</tabstop>
<tabstop>uiSceneWidthSpinBox</tabstop>
<tabstop>uiSceneHeightSpinBox</tabstop>
<tabstop>uiNodeGridSizeSpinBox</tabstop>
<tabstop>uiDrawingGridSizeSpinBox</tabstop>
<tabstop>uiRectangleSelectedItemCheckBox</tabstop>
<tabstop>uiDrawLinkStatusPointsCheckBox</tabstop>
<tabstop>uiShowInterfaceLabelsOnNewProject</tabstop>
<tabstop>uiShowGridOnNewProject</tabstop>
<tabstop>uiSnapToGridOnNewProject</tabstop>
<tabstop>uiLimitSizeNodeSymbolCheckBox</tabstop>
<tabstop>uiDefaultLabelFontPushButton</tabstop>
<tabstop>uiDefaultLabelColorPushButton</tabstop>
<tabstop>uiDefaultNoteFontPushButton</tabstop>
<tabstop>uiDefaultNoteColorPushButton</tabstop>
<tabstop>uiCheckForUpdateCheckBox</tabstop>
<tabstop>uiCrashReportCheckBox</tabstop>
<tabstop>uiStatsCheckBox</tabstop>
<tabstop>uiOverlayNotificationsCheckBox</tabstop>
<tabstop>uiExperimentalFeaturesCheckBox</tabstop>
<tabstop>uiHdpiCheckBox</tabstop>
<tabstop>uiMultiProfilesCheckBox</tabstop>
<tabstop>uiDirectFileUpload</tabstop>
<tabstop>uiRestoreDefaultsPushButton</tabstop>
<tabstop>uiMiscTabWidget</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@@ -209,6 +209,18 @@
</item>
</layout>
</widget>
<tabstops>
<tabstop>uiEnableVMCheckBox</tabstop>
<tabstop>uiGNS3VMEngineComboBox</tabstop>
<tabstop>uiVMListComboBox</tabstop>
<tabstop>uiRefreshPushButton</tabstop>
<tabstop>uiHeadlessCheckBox</tabstop>
<tabstop>uiRamSpinBox</tabstop>
<tabstop>uiCpuSpinBox</tabstop>
<tabstop>uiWhenExitKeepRadioButton</tabstop>
<tabstop>uiWhenExitSuspendRadioButton</tabstop>
<tabstop>uiWhenExitStopRadioButton</tabstop>
</tabstops>
<resources/>
<connections/>
<designerdata>

View File

@@ -125,6 +125,14 @@
</item>
</layout>
</widget>
<tabstops>
<tabstop>uiPreconfiguredCaptureReaderCommandComboBox</tabstop>
<tabstop>uiPreconfiguredCaptureReaderCommandPushButton</tabstop>
<tabstop>uiCaptureReaderCommandLineEdit</tabstop>
<tabstop>uiAutoStartCheckBox</tabstop>
<tabstop>uiCaptureAnalyzerCommandLineEdit</tabstop>
<tabstop>uiRestoreDefaultsPushButton</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>980</width>
<height>680</height>
<width>680</width>
<height>517</height>
</rect>
</property>
<property name="windowTitle">
@@ -36,6 +36,9 @@
<bold>true</bold>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="indentation">
<number>10</number>
</property>
@@ -73,6 +76,9 @@
</item>
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
@@ -81,8 +87,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>542</width>
<height>559</height>
<width>269</width>
<height>457</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
@@ -103,6 +109,9 @@
</item>
<item>
<widget class="QDialogButtonBox" name="uiButtonBox">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@@ -131,8 +140,8 @@
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>540</x>
<y>571</y>
<x>672</x>
<y>509</y>
</hint>
<hint type="destinationlabel">
<x>449</x>
@@ -147,8 +156,8 @@
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>540</x>
<y>571</y>
<x>672</x>
<y>509</y>
</hint>
<hint type="destinationlabel">
<x>449</x>

View File

@@ -29,7 +29,7 @@
<enum>QTabWidget::Rounded</enum>
</property>
<property name="currentIndex">
<number>0</number>
<number>1</number>
</property>
<widget class="QWidget" name="uiNewProjectTab">
<attribute name="title">
@@ -284,6 +284,19 @@
</item>
</layout>
</widget>
<tabstops>
<tabstop>uiProjectTabWidget</tabstop>
<tabstop>uiNameLineEdit</tabstop>
<tabstop>uiLocationLineEdit</tabstop>
<tabstop>uiLocationBrowserToolButton</tabstop>
<tabstop>uiOpenProjectPushButton</tabstop>
<tabstop>uiRecentProjectsPushButton</tabstop>
<tabstop>uiSettingsPushButton</tabstop>
<tabstop>uiProjectsTreeWidget</tabstop>
<tabstop>uiDeleteProjectButton</tabstop>
<tabstop>uiDuplicateProjectPushButton</tabstop>
<tabstop>uiRefreshProjectsPushButton</tabstop>
</tabstops>
<resources/>
<connections>
<connection>

View File

@@ -15,6 +15,8 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import shlex
import importlib
import hashlib
import re
@@ -108,3 +110,14 @@ def natural_sort_key(s):
* pc10
"""
return [int(text) if text.isdecimal() else text.lower() for text in re.split('([0-9]+)', s)]
def shlex_quote(s):
"""
Compatible shlex_quote to handle case where Windows needs double quotes around file names, not single quotes.
"""
if sys.platform.startswith("win"):
return s if re.match(r'^[-_\w./]+$', s) else '"%s"' % s.replace('"', '\\"')
else:
return shlex.quote(s)

View File

@@ -66,7 +66,7 @@ def bring_window_to_front_from_process_name(process_name, title=None):
elif title in win32gui.GetWindowText(hwnd):
set_foreground_window(hwnd)
return True
except psutil.Error:
except (OSError, psutil.Error):
continue
return False

View File

@@ -80,11 +80,10 @@ def get_windows_interfaces():
:returns: list of windows interfaces
"""
import win32com.client
import pywintypes
interfaces = []
try:
import win32com.client
locator = win32com.client.Dispatch("WbemScripting.SWbemLocator")
service = locator.ConnectServer(".", "root\cimv2")
network_configs = service.InstancesOf("Win32_NetworkAdapterConfiguration")
@@ -109,7 +108,7 @@ def get_windows_interfaces():
"netcard": adapter.name,
"netmask": netmask,
"type": "ethernet"})
except (AttributeError, pywintypes.com_error):
except (ImportError, AttributeError, pywintypes.com_error):
log.warning("Could not use the COM service to retrieve interface info, trying using the registry...")
return _get_windows_interfaces_from_registry()

View File

@@ -97,6 +97,7 @@ def sudo(*commands, parent=None, shell=False):
return False
return True
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)

View File

@@ -21,7 +21,7 @@ Thread to run a command and wait for its completion.
import tempfile
import subprocess
import shlex
from ..utils import shlex_quote
from ..qt import QtCore
import logging
@@ -63,7 +63,7 @@ class WaitForCommandWorker(QtCore.QObject):
timeout=self._timeout,
shell=self._shell)
except (OSError, subprocess.SubprocessError) as e:
command_string = " ".join(shlex.quote(s) for s in self._command)
command_string = " ".join(shlex_quote(s) for s in self._command)
self.error.emit('Could not execute command "{}": {}'.format(command_string, e), True)
return
self.finished.emit()

View File

@@ -19,7 +19,7 @@
Thread to run a command with administrator rights on Windows and wait for its completion.
"""
import shlex
from ..utils import shlex_quote
from ..qt import QtCore
import logging
@@ -69,7 +69,7 @@ class WaitForRunAsWorker(QtCore.QObject):
lpFile=program,
lpParameters=params)
except pywintypes.error as e:
command_string = " ".join(shlex.quote(s) for s in self._command)
command_string = " ".join(shlex_quote(s) for s in self._command)
self.error.emit('Could not execute command "{}": {}'.format(command_string, e), True)
return

View File

@@ -23,8 +23,8 @@
# or negative for a release candidate or beta (after the base version
# number has been incremented)
__version__ = "2.2.0rc5"
__version_info__ = (2, 2, 0, -99)
__version__ = "2.2.2"
__version_info__ = (2, 2, 2, 0)
# If it's a git checkout try to add the commit
if "dev" in __version__:

View File

@@ -37,7 +37,7 @@ def vncConsole(host, port, command):
"""
if len(command.strip(' ')) == 0:
log.warning('VNC client is not configured')
log.error("VNC client is not configured")
return
# replace the place-holders by the actual values
@@ -56,4 +56,3 @@ def vncConsole(host, port, command):
subprocess.Popen(args, env=os.environ)
except (OSError, ValueError, subprocess.SubprocessError) as e:
log.error("Could not start VNC program with command '{}': {}".format(command, e))
raise

View File

@@ -39,12 +39,12 @@ def test_spice_console_on_windows():
popen.assert_called_once_with('command localhost 2525')
def test_spice_console_on_linux_with_popen_issues():
with patch('subprocess.Popen', side_effect=OSError("Dummy")), \
patch('sys.platform', new="linux"):
with pytest.raises(OSError):
spiceConsole('localhost', '2525', 'command %h %p')
# def test_spice_console_on_linux_with_popen_issues():
# with patch('subprocess.Popen', side_effect=OSError("Dummy")), \
# patch('sys.platform', new="linux"):
#
# with pytest.raises(OSError):
# spiceConsole('localhost', '2525', 'command %h %p')
def test_spice_console_with_ipv6_support():

View File

@@ -37,9 +37,9 @@ def test_vnc_console_on_windows():
popen.assert_called_once_with('command localhost 6000 100')
def test_vnc_console_on_linux_with_popen_issues():
with patch('subprocess.Popen', side_effect=OSError("Dummy")), \
patch('sys.platform', new="linux"):
with pytest.raises(OSError):
vncConsole('localhost', 6000, 'command %h %p %P')
# def test_vnc_console_on_linux_with_popen_issues():
# with patch('subprocess.Popen', side_effect=OSError("Dummy")), \
# patch('sys.platform', new="linux"):
#
# with pytest.raises(OSError):
# vncConsole('localhost', 6000, 'command %h %p %P')