def getDestinationLabel(self, maxLength, includeLocale=False, includeHostname=False): """ Provides a short description of the destination. This is made up of two components, the base <ip addr>:<port> and an extra piece of information in parentheses. The IP address is scrubbed from private connections. Extra information is... - the port's purpose for exit connections - the locale and/or hostname if set to do so, the address isn't private, and isn't on the local network - nothing otherwise Arguments: maxLength - maximum length of the string returned includeLocale - possibly includes the locale includeHostname - possibly includes the hostname """ # the port and port derived data can be hidden by config or without includePort includePort = self.includePort and (CONFIG["features.connection.showExitPort"] or self.getType() != Category.EXIT) # destination of the connection ipLabel = "<scrubbed>" if self.isPrivate() else self.foreign.getIpAddr() portLabel = ":%s" % self.foreign.getPort() if includePort else "" dstAddress = ipLabel + portLabel # Only append the extra info if there's at least a couple characters of # space (this is what's needed for the country codes). if len(dstAddress) + 5 <= maxLength: spaceAvailable = maxLength - len(dstAddress) - 3 if self.getType() == Category.EXIT and includePort: purpose = connections.getPortUsage(self.foreign.getPort()) if purpose: # BitTorrent is a common protocol to truncate, so just use "Torrent" # if there's not enough room. if len(purpose) > spaceAvailable and purpose == "BitTorrent": purpose = "Torrent" # crops with a hyphen if too long purpose = uiTools.cropStr(purpose, spaceAvailable, endType = uiTools.Ending.HYPHEN) dstAddress += " (%s)" % purpose elif not connections.isIpAddressPrivate(self.foreign.getIpAddr()): extraInfo = [] conn = torTools.getConn() if includeLocale and not conn.isGeoipUnavailable(): foreignLocale = self.foreign.getLocale("??") extraInfo.append(foreignLocale) spaceAvailable -= len(foreignLocale) + 2 if includeHostname: dstHostname = self.foreign.getHostname() if dstHostname: # determines the full space available, taking into account the ", " # dividers if there's multiple pieces of extra data maxHostnameSpace = spaceAvailable - 2 * len(extraInfo) dstHostname = uiTools.cropStr(dstHostname, maxHostnameSpace) extraInfo.append(dstHostname) spaceAvailable -= len(dstHostname) if extraInfo: dstAddress += " (%s)" % ", ".join(extraInfo) return dstAddress[:maxLength]
def getDestinationLabel(self, maxLength, includeLocale=False, includeHostname=False): """ Provides a short description of the destination. This is made up of two components, the base <ip addr>:<port> and an extra piece of information in parentheses. The IP address is scrubbed from private connections. Extra information is... - the port's purpose for exit connections - the locale and/or hostname if set to do so, the address isn't private, and isn't on the local network - nothing otherwise Arguments: maxLength - maximum length of the string returned includeLocale - possibly includes the locale includeHostname - possibly includes the hostname """ # the port and port derived data can be hidden by config or without includePort includePort = self.includePort and ( CONFIG["features.connection.showExitPort"] or self.getType() != Category.EXIT) # destination of the connection ipLabel = "<scrubbed>" if self.isPrivate() else self.foreign.getIpAddr( ) portLabel = ":%s" % self.foreign.getPort() if includePort else "" dstAddress = ipLabel + portLabel # Only append the extra info if there's at least a couple characters of # space (this is what's needed for the country codes). if len(dstAddress) + 5 <= maxLength: spaceAvailable = maxLength - len(dstAddress) - 3 if self.getType() == Category.EXIT and includePort: purpose = connections.getPortUsage(self.foreign.getPort()) if purpose: # BitTorrent is a common protocol to truncate, so just use "Torrent" # if there's not enough room. if len(purpose ) > spaceAvailable and purpose == "BitTorrent": purpose = "Torrent" # crops with a hyphen if too long purpose = uiTools.cropStr(purpose, spaceAvailable, endType=uiTools.Ending.HYPHEN) dstAddress += " (%s)" % purpose elif not connections.isIpAddressPrivate(self.foreign.getIpAddr()): extraInfo = [] conn = torTools.getConn() if includeLocale and not conn.isGeoipUnavailable(): foreignLocale = self.foreign.getLocale("??") extraInfo.append(foreignLocale) spaceAvailable -= len(foreignLocale) + 2 if includeHostname: dstHostname = self.foreign.getHostname() if dstHostname: # determines the full space available, taking into account the ", " # dividers if there's multiple pieces of extra data maxHostnameSpace = spaceAvailable - 2 * len(extraInfo) dstHostname = uiTools.cropStr(dstHostname, maxHostnameSpace) extraInfo.append(dstHostname) spaceAvailable -= len(dstHostname) if extraInfo: dstAddress += " (%s)" % ", ".join(extraInfo) return dstAddress[:maxLength]
def showCountDialog(countType, counts): """ Provides a dialog with bar graphs and percentages for the given set of counts. Pressing any key closes the dialog. Arguments: countType - type of counts being presented counts - mapping of labels to counts """ isNoStats = not counts noStatsMsg = "Usage stats aren't available yet, press any key..." if isNoStats: popup, width, height = cli.popups.init(3, len(noStatsMsg) + 4) else: popup, width, height = cli.popups.init(4 + max(1, len(counts)), 80) if not popup: return try: control = cli.controller.getController() popup.win.box() # dialog title if countType == CountType.CLIENT_LOCALE: title = "Client Locales" elif countType == CountType.EXIT_PORT: title = "Exiting Port Usage" else: title = "" log.warn("Unrecognized count type: %s" % countType) popup.addstr(0, 0, title, curses.A_STANDOUT) if isNoStats: popup.addstr(1, 2, noStatsMsg, curses.A_BOLD | uiTools.getColor("cyan")) else: sortedCounts = sorted(counts.iteritems(), key=operator.itemgetter(1)) sortedCounts.reverse() # constructs string formatting for the max key and value display width keyWidth, valWidth, valueTotal = 3, 1, 0 for k, v in sortedCounts: keyWidth = max(keyWidth, len(k)) valWidth = max(valWidth, len(str(v))) valueTotal += v # extra space since we're adding usage informaion if countType == CountType.EXIT_PORT: keyWidth += EXIT_USAGE_WIDTH labelFormat = "%%-%is %%%ii (%%%%%%-2i)" % (keyWidth, valWidth) for i in range(height - 4): k, v = sortedCounts[i] # includes a port usage column if countType == CountType.EXIT_PORT: usage = connections.getPortUsage(k) if usage: keyFormat = "%%-%is %%s" % (keyWidth - EXIT_USAGE_WIDTH) k = keyFormat % (k, usage[:EXIT_USAGE_WIDTH - 3]) label = labelFormat % (k, v, v * 100 / valueTotal) popup.addstr(i + 1, 2, label, curses.A_BOLD | uiTools.getColor("green")) # All labels have the same size since they're based on the max widths. # If this changes then this'll need to be the max label width. labelWidth = len(label) # draws simple bar graph for percentages fillWidth = v * (width - 4 - labelWidth) / valueTotal for j in range(fillWidth): popup.addstr(i + 1, 3 + labelWidth + j, " ", curses.A_STANDOUT | uiTools.getColor("red")) popup.addstr(height - 2, 2, "Press any key...") popup.win.refresh() curses.cbreak() control.getScreen().getch() finally: cli.popups.finalize()
def showCountDialog(countType, counts): """ Provides a dialog with bar graphs and percentages for the given set of counts. Pressing any key closes the dialog. Arguments: countType - type of counts being presented counts - mapping of labels to counts """ isNoStats = not counts noStatsMsg = "Usage stats aren't available yet, press any key..." if isNoStats: popup, width, height = cli.popups.init(3, len(noStatsMsg) + 4) else: popup, width, height = cli.popups.init(4 + max(1, len(counts)), 80) if not popup: return try: control = cli.controller.getController() popup.win.box() # dialog title if countType == CountType.CLIENT_LOCALE: title = "Client Locales" elif countType == CountType.EXIT_PORT: title = "Exiting Port Usage" else: title = "" log.log(log.WARN, "Unrecognized count type: %s" % countType) popup.addstr(0, 0, title, curses.A_STANDOUT) if isNoStats: popup.addstr(1, 2, noStatsMsg, curses.A_BOLD | uiTools.getColor("cyan")) else: sortedCounts = sorted(counts.iteritems(), key=operator.itemgetter(1)) sortedCounts.reverse() # constructs string formatting for the max key and value display width keyWidth, valWidth, valueTotal = 3, 1, 0 for k, v in sortedCounts: keyWidth = max(keyWidth, len(k)) valWidth = max(valWidth, len(str(v))) valueTotal += v # extra space since we're adding usage informaion if countType == CountType.EXIT_PORT: keyWidth += EXIT_USAGE_WIDTH labelFormat = "%%-%is %%%ii (%%%%%%-2i)" % (keyWidth, valWidth) for i in range(height - 4): k, v = sortedCounts[i] # includes a port usage column if countType == CountType.EXIT_PORT: usage = connections.getPortUsage(k) if usage: keyFormat = "%%-%is %%s" % (keyWidth - EXIT_USAGE_WIDTH) k = keyFormat % (k, usage[:EXIT_USAGE_WIDTH - 3]) label = labelFormat % (k, v, v * 100 / valueTotal) popup.addstr(i + 1, 2, label, curses.A_BOLD | uiTools.getColor("green")) # All labels have the same size since they're based on the max widths. # If this changes then this'll need to be the max label width. labelWidth = len(label) # draws simple bar graph for percentages fillWidth = v * (width - 4 - labelWidth) / valueTotal for j in range(fillWidth): popup.addstr(i + 1, 3 + labelWidth + j, " ", curses.A_STANDOUT | uiTools.getColor("red")) popup.addstr(height - 2, 2, "Press any key...") popup.win.refresh() curses.cbreak() control.getScreen().getch() finally: cli.popups.finalize()