コード例 #1
0
    def draw(self, panel, width, height):
        # line of the graph's x-axis labeling
        labelingLine = graphPanel.GraphStats.getContentHeight(
            self) + panel.graphHeight - 2

        # if display is narrow, overwrites x-axis labels with avg / total stats
        if width <= COLLAPSE_WIDTH:
            # clears line
            panel.addstr(labelingLine, 0, " " * width)
            graphCol = min((width - 10) / 2, self.maxCol)

            primaryFooter = "%s, %s" % (self._getAvgLabel(True),
                                        self._getTotalLabel(True))
            secondaryFooter = "%s, %s" % (self._getAvgLabel(False),
                                          self._getTotalLabel(False))

            panel.addstr(labelingLine, 1, primaryFooter,
                         uiTools.getColor(self.getColor(True)))
            panel.addstr(labelingLine, graphCol + 6, secondaryFooter,
                         uiTools.getColor(self.getColor(False)))

        # provides accounting stats if enabled
        if self.isAccounting:
            if torTools.getConn().isAlive():
                status = self.accountingInfo["status"]

                hibernateColor = "green"
                if status == "soft": hibernateColor = "yellow"
                elif status == "hard": hibernateColor = "red"
                elif status == "":
                    # failed to be queried
                    status, hibernateColor = "unknown", "red"

                panel.addfstr(
                    labelingLine + 2, 0, "<b>Accounting (<%s>%s</%s>)</b>" %
                    (hibernateColor, status, hibernateColor))

                resetTime = self.accountingInfo["resetTime"]
                if not resetTime: resetTime = "unknown"
                panel.addstr(labelingLine + 2, 35,
                             "Time to reset: %s" % resetTime)

                used, total = self.accountingInfo["read"], self.accountingInfo[
                    "readLimit"]
                if used and total:
                    panel.addstr(labelingLine + 3, 2,
                                 "%s / %s" % (used, total),
                                 uiTools.getColor(self.getColor(True)))

                used, total = self.accountingInfo[
                    "written"], self.accountingInfo["writtenLimit"]
                if used and total:
                    panel.addstr(labelingLine + 3, 37,
                                 "%s / %s" % (used, total),
                                 uiTools.getColor(self.getColor(False)))
            else:
                panel.addfstr(labelingLine + 2, 0,
                              "<b>Accounting:</b> Connection Closed...")
コード例 #2
0
ファイル: fileDescriptorPopup.py プロジェクト: katmagic/arm
def draw(popup, properties):
  popup.clear()
  popup.win.box()
  
  # top label
  popup.addstr(0, 0, "Open File Descriptors:", curses.A_STANDOUT)
  
  if properties.errorMsg:
    popup.addstr(1, 2, properties.errorMsg, curses.A_BOLD | uiTools.getColor("red"))
  else:
    # text with file descriptor count and limit
    fdCount = len(properties.fdFile) + len(properties.fdConn) + len(properties.fdMisc)
    fdCountPer = 100 * fdCount / max(properties.fdLimit, 1)
    
    statsColor = "green"
    if fdCountPer >= 90: statsColor = "red"
    elif fdCountPer >= 50: statsColor = "yellow"
    
    countMsg = "%i / %i (%i%%)" % (fdCount, properties.fdLimit, fdCountPer)
    popup.addstr(1, 2, countMsg, curses.A_BOLD | uiTools.getColor(statsColor))
    
    # provides a progress bar reflecting the stats
    barWidth = popup.maxX - len(countMsg) - 6 # space between "[ ]" in progress bar
    barProgress = barWidth * fdCountPer / 100 # filled cells
    if fdCount > 0: barProgress = max(1, barProgress) # ensures one cell is filled unless really zero
    popup.addstr(1, len(countMsg) + 3, "[", curses.A_BOLD)
    popup.addstr(1, len(countMsg) + 4, " " * barProgress, curses.A_STANDOUT | uiTools.getColor(statsColor))
    popup.addstr(1, len(countMsg) + 4 + barWidth, "]", curses.A_BOLD)
    
    popup.win.hline(2, 1, curses.ACS_HLINE, popup.maxX - 2)
    
    # scrollable file descriptor listing
    lineNum = 3
    entryNum = properties.scroll
    while lineNum <= popup.maxY - 2:
      if entryNum < len(properties.fdFile):
        line = properties.fdFile[entryNum]
        color = "green"
      elif entryNum < len(properties.fdFile) + len(properties.fdMisc):
        line = properties.fdMisc[entryNum - len(properties.fdFile)]
        color = "cyan"
      else:
        line = properties.fdConn[entryNum - len(properties.fdFile) - len(properties.fdMisc)]
        color = "blue"
      
      popup.addstr(lineNum, 2, line, curses.A_BOLD | uiTools.getColor(color))
      lineNum += 1
      entryNum += 1
  
  popup.refresh()
コード例 #3
0
ファイル: menu.py プロジェクト: lnrsoft/arm
def _drawSubmenu(cursor, level, top, left):
    selectionHierarchy = cursor.getSelection().getHierarchy()

    # checks if there's nothing to display
    if len(selectionHierarchy) < level + 2: return

    # fetches the submenu and selection we're displaying
    submenu = selectionHierarchy[level]
    selection = selectionHierarchy[level + 1]

    # gets the size of the prefix, middle, and suffix columns
    allLabelSets = [entry.getLabel() for entry in submenu.getChildren()]
    prefixColSize = max([len(entry[0]) for entry in allLabelSets])
    middleColSize = max([len(entry[1]) for entry in allLabelSets])
    suffixColSize = max([len(entry[2]) for entry in allLabelSets])

    # formatted string so we can display aligned menu entries
    labelFormat = " %%-%is%%-%is%%-%is " % (prefixColSize, middleColSize,
                                            suffixColSize)
    menuWidth = len(labelFormat % ("", "", ""))

    popup, _, _ = cli.popups.init(len(submenu.getChildren()),
                                  menuWidth,
                                  top,
                                  left,
                                  belowStatic=False)
    if not popup: return

    try:
        # sets the background color
        popup.win.bkgd(' ', curses.A_STANDOUT | uiTools.getColor("red"))

        drawTop, selectionTop = 0, 0
        for menuItem in submenu.getChildren():
            if menuItem == selection:
                drawFormat = curses.A_BOLD | uiTools.getColor("white")
                selectionTop = drawTop
            else:
                drawFormat = curses.A_NORMAL

            popup.addstr(drawTop, 0, labelFormat % menuItem.getLabel(),
                         drawFormat)
            drawTop += 1

        popup.win.refresh()

        # shows the next submenu
        _drawSubmenu(cursor, level + 1, top + selectionTop, left + menuWidth)
    finally:
        cli.popups.finalize()
コード例 #4
0
ファイル: circEntry.py プロジェクト: lnrsoft/arm
 def getDetails(self, width):
     if not self.isBuilt:
         detailFormat = curses.A_BOLD | uiTools.getColor(
             connEntry.CATEGORY_COLOR[self.getType()])
         return [("Building Circuit...", detailFormat)]
     else:
         return connEntry.ConnectionLine.getDetails(self, width)
コード例 #5
0
def _drawSortSelection(popup, y, x, prefix, options, optionColors):
  """
  Draws a series of comma separated sort selections. The whole line is bold
  and sort options also have their specified color. Example:
  
    Current Order: Man Page Entry, Option Name, Is Default
  
  Arguments:
    popup        - panel in which to draw sort selection
    y            - vertical location
    x            - horizontal location
    prefix       - initial string description
    options      - sort options to be shown
    optionColors - mappings of options to their color
  """
  
  popup.addstr(y, x, prefix, curses.A_BOLD)
  x += len(prefix)
  
  for i in range(len(options)):
    sortType = options[i]
    sortColor = uiTools.getColor(optionColors.get(sortType, "white"))
    popup.addstr(y, x, sortType, sortColor | curses.A_BOLD)
    x += len(sortType)
    
    # comma divider between options, if this isn't the last
    if i < len(options) - 1:
      popup.addstr(y, x, ", ", curses.A_BOLD)
      x += 2
コード例 #6
0
ファイル: configPanel.py プロジェクト: gsathya/arm
    def _drawSelectionPanel(self, selection, width, detailPanelHeight, isScrollbarVisible):
        """
    Renders a panel for the selected configuration option.
    """

        # This is a solid border unless the scrollbar is visible, in which case a
        # 'T' pipe connects the border to the bar.
        uiTools.drawBox(self, 0, 0, width, detailPanelHeight + 1)
        if isScrollbarVisible:
            self.addch(detailPanelHeight, 1, curses.ACS_TTEE)

        selectionFormat = curses.A_BOLD | uiTools.getColor(CATEGORY_COLOR[selection.get(Field.CATEGORY)])

        # first entry:
        # <option> (<category> Option)
        optionLabel = " (%s Option)" % selection.get(Field.CATEGORY)
        self.addstr(1, 2, selection.get(Field.OPTION) + optionLabel, selectionFormat)

        # second entry:
        # Value: <value> ([default|custom], <type>, usage: <argument usage>)
        if detailPanelHeight >= 3:
            valueAttr = []
            valueAttr.append("default" if selection.get(Field.IS_DEFAULT) else "custom")
            valueAttr.append(selection.get(Field.TYPE))
            valueAttr.append("usage: %s" % (selection.get(Field.ARG_USAGE)))
            valueAttrLabel = ", ".join(valueAttr)

            valueLabelWidth = width - 12 - len(valueAttrLabel)
            valueLabel = uiTools.cropStr(selection.get(Field.VALUE), valueLabelWidth)

            self.addstr(2, 2, "Value: %s (%s)" % (valueLabel, valueAttrLabel), selectionFormat)

        # remainder is filled with the man page description
        descriptionHeight = max(0, detailPanelHeight - 3)
        descriptionContent = "Description: " + selection.get(Field.DESCRIPTION)

        for i in range(descriptionHeight):
            # checks if we're done writing the description
            if not descriptionContent:
                break

            # there's a leading indent after the first line
            if i > 0:
                descriptionContent = "  " + descriptionContent

            # we only want to work with content up until the next newline
            if "\n" in descriptionContent:
                lineContent, descriptionContent = descriptionContent.split("\n", 1)
            else:
                lineContent, descriptionContent = descriptionContent, ""

            if i != descriptionHeight - 1:
                # there's more lines to display
                msg, remainder = uiTools.cropStr(lineContent, width - 3, 4, 4, uiTools.Ending.HYPHEN, True)
                descriptionContent = remainder.strip() + descriptionContent
            else:
                # this is the last line, end it with an ellipse
                msg = uiTools.cropStr(lineContent, width - 3, 4, 4)

            self.addstr(3 + i, 2, msg, selectionFormat)
コード例 #7
0
ファイル: configPanel.py プロジェクト: JustMe23/arm
 def draw(self, width, height):
   self.valsLock.acquire()
   
   # panel with details for the current selection
   detailPanelHeight = self._config["features.config.selectionDetails.height"]
   isScrollbarVisible = False
   if detailPanelHeight == 0 or detailPanelHeight + 2 >= height:
     # no detail panel
     detailPanelHeight = 0
     scrollLoc = self.scroller.getScrollLoc(self._getConfigOptions(), height - 1)
     cursorSelection = self.getSelection()
     isScrollbarVisible = len(self._getConfigOptions()) > height - 1
   else:
     # Shrink detail panel if there isn't sufficient room for the whole
     # thing. The extra line is for the bottom border.
     detailPanelHeight = min(height - 1, detailPanelHeight + 1)
     scrollLoc = self.scroller.getScrollLoc(self._getConfigOptions(), height - 1 - detailPanelHeight)
     cursorSelection = self.getSelection()
     isScrollbarVisible = len(self._getConfigOptions()) > height - detailPanelHeight - 1
     
     if cursorSelection != None:
       self._drawSelectionPanel(cursorSelection, width, detailPanelHeight, isScrollbarVisible)
   
   # draws the top label
   if self.isTitleVisible():
     configType = "Tor" if self.configType == State.TOR else "Arm"
     hiddenMsg = "press 'a' to hide most options" if self.showAll else "press 'a' to show all options"
     titleLabel = "%s Configuration (%s):" % (configType, hiddenMsg)
     self.addstr(0, 0, titleLabel, curses.A_STANDOUT)
   
   # draws left-hand scroll bar if content's longer than the height
   scrollOffset = 1
   if isScrollbarVisible:
     scrollOffset = 3
     self.addScrollBar(scrollLoc, scrollLoc + height - detailPanelHeight - 1, len(self._getConfigOptions()), 1 + detailPanelHeight)
   
   optionWidth = self._config["features.config.state.colWidth.option"]
   valueWidth = self._config["features.config.state.colWidth.value"]
   descriptionWidth = max(0, width - scrollOffset - optionWidth - valueWidth - 2)
   
   # if the description column is overly long then use its space for the
   # value instead
   if descriptionWidth > 80:
     valueWidth += descriptionWidth - 80
     descriptionWidth = 80
   
   for lineNum in range(scrollLoc, len(self._getConfigOptions())):
     entry = self._getConfigOptions()[lineNum]
     drawLine = lineNum + detailPanelHeight + 1 - scrollLoc
     
     lineFormat = curses.A_NORMAL if entry.get(Field.IS_DEFAULT) else curses.A_BOLD
     if entry.get(Field.CATEGORY): lineFormat |= uiTools.getColor(CATEGORY_COLOR[entry.get(Field.CATEGORY)])
     if entry == cursorSelection: lineFormat |= curses.A_STANDOUT
     
     lineText = entry.getLabel(optionWidth, valueWidth, descriptionWidth)
     self.addstr(drawLine, scrollOffset, lineText, lineFormat)
     
     if drawLine >= height: break
   
   self.valsLock.release()
コード例 #8
0
 def draw(self, width, height):
   self.valsLock.acquire()
   
   # panel with details for the current selection
   detailPanelHeight = CONFIG["features.config.selectionDetails.height"]
   isScrollbarVisible = False
   if detailPanelHeight == 0 or detailPanelHeight + 2 >= height:
     # no detail panel
     detailPanelHeight = 0
     scrollLoc = self.scroller.getScrollLoc(self._getConfigOptions(), height - 1)
     cursorSelection = self.getSelection()
     isScrollbarVisible = len(self._getConfigOptions()) > height - 1
   else:
     # Shrink detail panel if there isn't sufficient room for the whole
     # thing. The extra line is for the bottom border.
     detailPanelHeight = min(height - 1, detailPanelHeight + 1)
     scrollLoc = self.scroller.getScrollLoc(self._getConfigOptions(), height - 1 - detailPanelHeight)
     cursorSelection = self.getSelection()
     isScrollbarVisible = len(self._getConfigOptions()) > height - detailPanelHeight - 1
     
     if cursorSelection != None:
       self._drawSelectionPanel(cursorSelection, width, detailPanelHeight, isScrollbarVisible)
   
   # draws the top label
   if self.isTitleVisible():
     configType = "Tor" if self.configType == State.TOR else "Arm"
     hiddenMsg = "press 'a' to hide most options" if self.showAll else "press 'a' to show all options"
     titleLabel = "%s Configuration (%s):" % (configType, hiddenMsg)
     self.addstr(0, 0, titleLabel, curses.A_STANDOUT)
   
   # draws left-hand scroll bar if content's longer than the height
   scrollOffset = 1
   if isScrollbarVisible:
     scrollOffset = 3
     self.addScrollBar(scrollLoc, scrollLoc + height - detailPanelHeight - 1, len(self._getConfigOptions()), 1 + detailPanelHeight)
   
   optionWidth = CONFIG["features.config.state.colWidth.option"]
   valueWidth = CONFIG["features.config.state.colWidth.value"]
   descriptionWidth = max(0, width - scrollOffset - optionWidth - valueWidth - 2)
   
   # if the description column is overly long then use its space for the
   # value instead
   if descriptionWidth > 80:
     valueWidth += descriptionWidth - 80
     descriptionWidth = 80
   
   for lineNum in range(scrollLoc, len(self._getConfigOptions())):
     entry = self._getConfigOptions()[lineNum]
     drawLine = lineNum + detailPanelHeight + 1 - scrollLoc
     
     lineFormat = curses.A_NORMAL if entry.get(Field.IS_DEFAULT) else curses.A_BOLD
     if entry.get(Field.CATEGORY): lineFormat |= uiTools.getColor(CATEGORY_COLOR[entry.get(Field.CATEGORY)])
     if entry == cursorSelection: lineFormat |= curses.A_STANDOUT
     
     lineText = entry.getLabel(optionWidth, valueWidth, descriptionWidth)
     self.addstr(drawLine, scrollOffset, lineText, lineFormat)
     
     if drawLine >= height: break
   
   self.valsLock.release()
コード例 #9
0
ファイル: bandwidthStats.py プロジェクト: gsathya/arm
 def draw(self, panel, width, height):
   # line of the graph's x-axis labeling
   labelingLine = graphPanel.GraphStats.getContentHeight(self) + panel.graphHeight - 2
   
   # if display is narrow, overwrites x-axis labels with avg / total stats
   if width <= COLLAPSE_WIDTH:
     # clears line
     panel.addstr(labelingLine, 0, " " * width)
     graphCol = min((width - 10) / 2, self.maxCol)
     
     primaryFooter = "%s, %s" % (self._getAvgLabel(True), self._getTotalLabel(True))
     secondaryFooter = "%s, %s" % (self._getAvgLabel(False), self._getTotalLabel(False))
     
     panel.addstr(labelingLine, 1, primaryFooter, uiTools.getColor(self.getColor(True)))
     panel.addstr(labelingLine, graphCol + 6, secondaryFooter, uiTools.getColor(self.getColor(False)))
   
   # provides accounting stats if enabled
   if self.isAccounting:
     if torTools.getConn().isAlive():
       status = self.accountingInfo["status"]
       
       hibernateColor = "green"
       if status == "soft": hibernateColor = "yellow"
       elif status == "hard": hibernateColor = "red"
       elif status == "":
         # failed to be queried
         status, hibernateColor = "unknown", "red"
       
       panel.addstr(labelingLine + 2, 0, "Accounting (", curses.A_BOLD)
       panel.addstr(labelingLine + 2, 12, status, curses.A_BOLD | uiTools.getColor(hibernateColor))
       panel.addstr(labelingLine + 2, 12 + len(status), ")", curses.A_BOLD)
       
       resetTime = self.accountingInfo["resetTime"]
       if not resetTime: resetTime = "unknown"
       panel.addstr(labelingLine + 2, 35, "Time to reset: %s" % resetTime)
       
       used, total = self.accountingInfo["read"], self.accountingInfo["readLimit"]
       if used and total:
         panel.addstr(labelingLine + 3, 2, "%s / %s" % (used, total), uiTools.getColor(self.getColor(True)))
       
       used, total = self.accountingInfo["written"], self.accountingInfo["writtenLimit"]
       if used and total:
         panel.addstr(labelingLine + 3, 37, "%s / %s" % (used, total), uiTools.getColor(self.getColor(False)))
     else:
       panel.addstr(labelingLine + 2, 0, "Accounting:", curses.A_BOLD)
       panel.addstr(labelingLine + 2, 12, "Connection Closed...")
コード例 #10
0
 def _drawSelectionPanel(self, selection, width, detailPanelHeight, isScrollbarVisible):
   """
   Renders a panel for the selected configuration option.
   """
   
   # This is a solid border unless the scrollbar is visible, in which case a
   # 'T' pipe connects the border to the bar.
   uiTools.drawBox(self, 0, 0, width, detailPanelHeight + 1)
   if isScrollbarVisible: self.addch(detailPanelHeight, 1, curses.ACS_TTEE)
   
   selectionFormat = curses.A_BOLD | uiTools.getColor(CATEGORY_COLOR[selection.get(Field.CATEGORY)])
   
   # first entry:
   # <option> (<category> Option)
   optionLabel =" (%s Option)" % selection.get(Field.CATEGORY)
   self.addstr(1, 2, selection.get(Field.OPTION) + optionLabel, selectionFormat)
   
   # second entry:
   # Value: <value> ([default|custom], <type>, usage: <argument usage>)
   if detailPanelHeight >= 3:
     valueAttr = []
     valueAttr.append("default" if selection.get(Field.IS_DEFAULT) else "custom")
     valueAttr.append(selection.get(Field.TYPE))
     valueAttr.append("usage: %s" % (selection.get(Field.ARG_USAGE)))
     valueAttrLabel = ", ".join(valueAttr)
     
     valueLabelWidth = width - 12 - len(valueAttrLabel)
     valueLabel = uiTools.cropStr(selection.get(Field.VALUE), valueLabelWidth)
     
     self.addstr(2, 2, "Value: %s (%s)" % (valueLabel, valueAttrLabel), selectionFormat)
   
   # remainder is filled with the man page description
   descriptionHeight = max(0, detailPanelHeight - 3)
   descriptionContent = "Description: " + selection.get(Field.DESCRIPTION)
   
   for i in range(descriptionHeight):
     # checks if we're done writing the description
     if not descriptionContent: break
     
     # there's a leading indent after the first line
     if i > 0: descriptionContent = "  " + descriptionContent
     
     # we only want to work with content up until the next newline
     if "\n" in descriptionContent:
       lineContent, descriptionContent = descriptionContent.split("\n", 1)
     else: lineContent, descriptionContent = descriptionContent, ""
     
     if i != descriptionHeight - 1:
       # there's more lines to display
       msg, remainder = uiTools.cropStr(lineContent, width - 3, 4, 4, uiTools.Ending.HYPHEN, True)
       descriptionContent = remainder.strip() + descriptionContent
     else:
       # this is the last line, end it with an ellipse
       msg = uiTools.cropStr(lineContent, width - 3, 4, 4)
     
     self.addstr(3 + i, 2, msg, selectionFormat)
コード例 #11
0
ファイル: menu.py プロジェクト: JustMe23/arm
def _drawSubmenu(cursor, level, top, left):
  selectionHierarchy = cursor.getSelection().getHierarchy()
  
  # checks if there's nothing to display
  if len(selectionHierarchy) < level + 2: return
  
  # fetches the submenu and selection we're displaying
  submenu = selectionHierarchy[level]
  selection = selectionHierarchy[level + 1]
  
  # gets the size of the prefix, middle, and suffix columns
  allLabelSets = [entry.getLabel() for entry in submenu.getChildren()]
  prefixColSize = max([len(entry[0]) for entry in allLabelSets])
  middleColSize = max([len(entry[1]) for entry in allLabelSets])
  suffixColSize = max([len(entry[2]) for entry in allLabelSets])
  
  # formatted string so we can display aligned menu entries
  labelFormat = " %%-%is%%-%is%%-%is " % (prefixColSize, middleColSize, suffixColSize)
  menuWidth = len(labelFormat % ("", "", ""))
  
  popup, _, _ = cli.popups.init(len(submenu.getChildren()), menuWidth, top, left, belowStatic = False)
  if not popup: return
  
  try:
    # sets the background color
    popup.win.bkgd(' ', curses.A_STANDOUT | uiTools.getColor("red"))
    
    drawTop, selectionTop = 0, 0
    for menuItem in submenu.getChildren():
      if menuItem == selection:
        drawFormat = curses.A_BOLD | uiTools.getColor("white")
        selectionTop = drawTop
      else: drawFormat = curses.A_NORMAL
      
      popup.addstr(drawTop, 0, labelFormat % menuItem.getLabel(), drawFormat)
      drawTop += 1
    
    popup.win.refresh()
    
    # shows the next submenu
    _drawSubmenu(cursor, level + 1, top + selectionTop, left + menuWidth)
  finally: cli.popups.finalize()
コード例 #12
0
ファイル: configPanel.py プロジェクト: katmagic/arm
 def draw(self, subwindow, width, height):
   self.valsLock.acquire()
   
   # draws the top label
   titleLabel = "%s Configuration:" % ("Tor" if self.configType == TOR_STATE else "Arm")
   self.addstr(0, 0, titleLabel, curses.A_STANDOUT)
   
   # panel with details for the current selection
   detailPanelHeight = self._config["features.config.selectionDetails.height"]
   if detailPanelHeight == 0 or detailPanelHeight + 2 >= height:
     # no detail panel
     detailPanelHeight = 0
     scrollLoc = self.scroller.getScrollLoc(self.confContents, height - 1)
     cursorSelection = self.getSelection()
   else:
     # Shrink detail panel if there isn't sufficient room for the whole
     # thing. The extra line is for the bottom border.
     detailPanelHeight = min(height - 1, detailPanelHeight + 1)
     scrollLoc = self.scroller.getScrollLoc(self.confContents, height - 1 - detailPanelHeight)
     cursorSelection = self.getSelection()
     
     self._drawSelectionPanel(cursorSelection, width, detailPanelHeight, titleLabel)
   
   # draws left-hand scroll bar if content's longer than the height
   scrollOffset = 0
   if len(self.confContents) > height - detailPanelHeight - 1:
     scrollOffset = 3
     self.addScrollBar(scrollLoc, scrollLoc + height - detailPanelHeight - 1, len(self.confContents), 1 + detailPanelHeight)
   
   optionWidth = self._config["features.config.state.colWidth.option"]
   valueWidth = self._config["features.config.state.colWidth.value"]
   descriptionWidth = max(0, width - scrollOffset - optionWidth - valueWidth - 2)
   
   for lineNum in range(scrollLoc, len(self.confContents)):
     entry = self.confContents[lineNum]
     drawLine = lineNum + detailPanelHeight + 1 - scrollLoc
     
     optionLabel = uiTools.cropStr(entry.get(FIELD_OPTION), optionWidth)
     valueLabel = uiTools.cropStr(entry.get(FIELD_VALUE), valueWidth)
     
     # ends description at the first newline
     descriptionLabel = uiTools.cropStr(entry.get(FIELD_DESCRIPTION).split("\n")[0], descriptionWidth, None)
     
     lineFormat = curses.A_NORMAL if entry.get(FIELD_IS_DEFAULT) else curses.A_BOLD
     if entry.get(FIELD_CATEGORY): lineFormat |= uiTools.getColor(CATEGORY_COLOR[entry.get(FIELD_CATEGORY)])
     if entry == cursorSelection: lineFormat |= curses.A_STANDOUT
     
     lineTextLayout = "%%-%is %%-%is %%-%is" % (optionWidth, valueWidth, descriptionWidth)
     lineText = lineTextLayout % (optionLabel, valueLabel, descriptionLabel)
     self.addstr(drawLine, scrollOffset, lineText, lineFormat)
     
     if drawLine >= height: break
   
   self.valsLock.release()
コード例 #13
0
ファイル: connEntry.py プロジェクト: refnode/arm
 def _getDetails(self, width):
   """
   Provides details on the connection, correlated against available consensus
   data.
   
   Arguments:
     width - available space to display in
   """
   
   detailFormat = curses.A_BOLD | uiTools.getColor(CATEGORY_COLOR[self.getType()])
   return [(line, detailFormat) for line in self._getDetailContent(width)]
コード例 #14
0
    def _getDetails(self, width):
        """
    Provides details on the connection, correlated against available consensus
    data.
    
    Arguments:
      width - available space to display in
    """

        detailFormat = curses.A_BOLD | uiTools.getColor(
            CATEGORY_COLOR[self.getType()])
        return [(line, detailFormat) for line in self._getDetailContent(width)]
コード例 #15
0
ファイル: descriptorPopup.py プロジェクト: katmagic/arm
def draw(popup, properties):
  popup.clear()
  popup.win.box()
  xOffset = 2
  
  if properties.text:
    if properties.fingerprint: popup.addstr(0, 0, "Consensus Descriptor (%s):" % properties.fingerprint, curses.A_STANDOUT)
    else: popup.addstr(0, 0, "Consensus Descriptor:", curses.A_STANDOUT)
    
    isEncryption = False          # true if line is part of an encryption block
    
    # checks if first line is in an encryption block
    for i in range(0, properties.scroll):
      lineText = properties.text[i].strip()
      if lineText in SIG_START_KEYS: isEncryption = True
      elif lineText in SIG_END_KEYS: isEncryption = False
    
    pageHeight = popup.maxY - 2
    numFieldWidth = int(math.log10(len(properties.text))) + 1
    lineNum = 1
    for i in range(properties.scroll, min(len(properties.text), properties.scroll + pageHeight)):
      lineText = properties.text[i].strip()
      
      numOffset = 0     # offset for line numbering
      if properties.showLineNum:
        popup.addstr(lineNum, xOffset, ("%%%ii" % numFieldWidth) % (i + 1), curses.A_BOLD | uiTools.getColor(LINE_NUM_COLOR))
        numOffset = numFieldWidth + 1
      
      if lineText:
        keyword = lineText.split()[0]   # first word of line
        remainder = lineText[len(keyword):]
        keywordFormat = curses.A_BOLD | uiTools.getColor(properties.entryColor)
        remainderFormat = uiTools.getColor(properties.entryColor)
        
        if lineText.startswith(HEADER_PREFIX[0]) or lineText.startswith(HEADER_PREFIX[1]):
          keyword, remainder = lineText, ""
          keywordFormat = curses.A_BOLD | uiTools.getColor(HEADER_COLOR)
        if lineText == UNRESOLVED_MSG or lineText == ERROR_MSG:
          keyword, remainder = lineText, ""
        if lineText in SIG_START_KEYS:
          keyword, remainder = lineText, ""
          isEncryption = True
          keywordFormat = curses.A_BOLD | uiTools.getColor(SIG_COLOR)
        elif lineText in SIG_END_KEYS:
          keyword, remainder = lineText, ""
          isEncryption = False
          keywordFormat = curses.A_BOLD | uiTools.getColor(SIG_COLOR)
        elif isEncryption:
          keyword, remainder = lineText, ""
          keywordFormat = uiTools.getColor(SIG_COLOR)
        
        lineNum, xLoc = controller.addstr_wrap(popup, lineNum, 0, keyword, keywordFormat, xOffset + numOffset, popup.maxX - 1, popup.maxY - 1)
        lineNum, xLoc = controller.addstr_wrap(popup, lineNum, xLoc, remainder, remainderFormat, xOffset + numOffset, popup.maxX - 1, popup.maxY - 1)
      
      lineNum += 1
      if lineNum > pageHeight: break
      
  popup.refresh()
コード例 #16
0
ファイル: menu.py プロジェクト: lnrsoft/arm
def showMenu():
    popup, _, _ = cli.popups.init(1, belowStatic=False)
    if not popup: return
    control = cli.controller.getController()

    try:
        # generates the menu and uses the initial selection of the first item in
        # the file menu
        menu = cli.menu.actions.makeMenu()
        cursor = MenuCursor(menu.getChildren()[0].getChildren()[0])

        while not cursor.isDone():
            # sets the background color
            popup.win.clear()
            popup.win.bkgd(' ', curses.A_STANDOUT | uiTools.getColor("red"))
            selectionHierarchy = cursor.getSelection().getHierarchy()

            # provide a message saying how to close the menu
            control.setMsg("Press m or esc to close the menu.", curses.A_BOLD,
                           True)

            # renders the menu bar, noting where the open submenu is positioned
            drawLeft, selectionLeft = 0, 0

            for topLevelItem in menu.getChildren():
                drawFormat = curses.A_BOLD
                if topLevelItem == selectionHierarchy[1]:
                    drawFormat |= curses.A_UNDERLINE
                    selectionLeft = drawLeft

                drawLabel = " %s " % topLevelItem.getLabel()[1]
                popup.addstr(0, drawLeft, drawLabel, drawFormat)
                popup.addch(0, drawLeft + len(drawLabel), curses.ACS_VLINE)

                drawLeft += len(drawLabel) + 1

            # recursively shows opened submenus
            _drawSubmenu(cursor, 1, 1, selectionLeft)

            popup.win.refresh()

            curses.cbreak()
            key = control.getScreen().getch()
            cursor.handleKey(key)

            # redraws the rest of the interface if we're rendering on it again
            if not cursor.isDone(): control.redraw()
    finally:
        control.setMsg()
        cli.popups.finalize()
コード例 #17
0
ファイル: menu.py プロジェクト: JustMe23/arm
def showMenu():
  popup, _, _ = cli.popups.init(1, belowStatic = False)
  if not popup: return
  control = cli.controller.getController()
  
  try:
    # generates the menu and uses the initial selection of the first item in
    # the file menu
    menu = cli.menu.actions.makeMenu()
    cursor = MenuCursor(menu.getChildren()[0].getChildren()[0])
    
    while not cursor.isDone():
      # sets the background color
      popup.win.clear()
      popup.win.bkgd(' ', curses.A_STANDOUT | uiTools.getColor("red"))
      selectionHierarchy = cursor.getSelection().getHierarchy()
      
      # provide a message saying how to close the menu
      control.setMsg("Press m or esc to close the menu.", curses.A_BOLD, True)
      
      # renders the menu bar, noting where the open submenu is positioned
      drawLeft, selectionLeft = 0, 0
      
      for topLevelItem in menu.getChildren():
        drawFormat = curses.A_BOLD
        if topLevelItem == selectionHierarchy[1]:
          drawFormat |= curses.A_UNDERLINE
          selectionLeft = drawLeft
        
        drawLabel = " %s " % topLevelItem.getLabel()[1]
        popup.addstr(0, drawLeft, drawLabel, drawFormat)
        popup.addch(0, drawLeft + len(drawLabel), curses.ACS_VLINE)
        
        drawLeft += len(drawLabel) + 1
      
      # recursively shows opened submenus
      _drawSubmenu(cursor, 1, 1, selectionLeft)
      
      popup.win.refresh()
      
      curses.cbreak()
      key = control.getScreen().getch()
      cursor.handleKey(key)
      
      # redraws the rest of the interface if we're rendering on it again
      if not cursor.isDone(): control.redraw()
  finally:
    control.setMsg()
    cli.popups.finalize()
コード例 #18
0
ファイル: circEntry.py プロジェクト: lnrsoft/arm
    def _getListingEntry(self, width, currentTime, listingType):
        lineFormat = uiTools.getColor(connEntry.CATEGORY_COLOR[self.getType()])

        # The required widths are the sum of the following:
        # initial space (1 character)
        # bracketing (3 characters)
        # placementLabel (14 characters)
        # gap between etc and placement label (5 characters)

        baselineSpace = 14 + 5

        dst, etc = "", ""
        if listingType == entries.ListingType.IP_ADDRESS:
            # TODO: include hostname when that's available
            # dst width is derived as:
            # src (21) + dst (26) + divider (7) + right gap (2) - bracket (3) = 53 char
            dst = "%-53s" % self.getDestinationLabel(53, includeLocale=True)

            # fills the nickname into the empty space here
            dst = "%s%-25s   " % (
                dst[:25], uiTools.cropStr(self.foreign.getNickname(), 25, 0))

            etc = self.getEtcContent(width - baselineSpace - len(dst),
                                     listingType)
        elif listingType == entries.ListingType.HOSTNAME:
            # min space for the hostname is 40 characters
            etc = self.getEtcContent(width - baselineSpace - 40, listingType)
            dstLayout = "%%-%is" % (width - baselineSpace - len(etc))
            dst = dstLayout % self.foreign.getHostname(
                self.foreign.getIpAddr())
        elif listingType == entries.ListingType.FINGERPRINT:
            # dst width is derived as:
            # src (9) + dst (40) + divider (7) + right gap (2) - bracket (3) = 55 char
            dst = "%-55s" % self.foreign.getFingerprint()
            etc = self.getEtcContent(width - baselineSpace - len(dst),
                                     listingType)
        else:
            # min space for the nickname is 56 characters
            etc = self.getEtcContent(width - baselineSpace - 56, listingType)
            dstLayout = "%%-%is" % (width - baselineSpace - len(etc))
            dst = dstLayout % self.foreign.getNickname()

        return ((dst + etc, lineFormat),
                (" " * (width - baselineSpace - len(dst) - len(etc) + 5),
                 lineFormat), ("%-14s" % self.placementLabel, lineFormat))
コード例 #19
0
ファイル: circEntry.py プロジェクト: JustMe23/arm
 def _getListingEntry(self, width, currentTime, listingType):
   lineFormat = uiTools.getColor(connEntry.CATEGORY_COLOR[self.getType()])
   
   # The required widths are the sum of the following:
   # initial space (1 character)
   # bracketing (3 characters)
   # placementLabel (14 characters)
   # gap between etc and placement label (5 characters)
   
   baselineSpace = 14 + 5
   
   dst, etc = "", ""
   if listingType == entries.ListingType.IP_ADDRESS:
     # TODO: include hostname when that's available
     # dst width is derived as:
     # src (21) + dst (26) + divider (7) + right gap (2) - bracket (3) = 53 char
     dst = "%-53s" % self.getDestinationLabel(53, includeLocale = True)
     
     # fills the nickname into the empty space here
     dst = "%s%-25s   " % (dst[:25], uiTools.cropStr(self.foreign.getNickname(), 25, 0))
     
     etc = self.getEtcContent(width - baselineSpace - len(dst), listingType)
   elif listingType == entries.ListingType.HOSTNAME:
     # min space for the hostname is 40 characters
     etc = self.getEtcContent(width - baselineSpace - 40, listingType)
     dstLayout = "%%-%is" % (width - baselineSpace - len(etc))
     dst = dstLayout % self.foreign.getHostname(self.foreign.getIpAddr())
   elif listingType == entries.ListingType.FINGERPRINT:
     # dst width is derived as:
     # src (9) + dst (40) + divider (7) + right gap (2) - bracket (3) = 55 char
     dst = "%-55s" % self.foreign.getFingerprint()
     etc = self.getEtcContent(width - baselineSpace - len(dst), listingType)
   else:
     # min space for the nickname is 56 characters
     etc = self.getEtcContent(width - baselineSpace - 56, listingType)
     dstLayout = "%%-%is" % (width - baselineSpace - len(etc))
     dst = dstLayout % self.foreign.getNickname()
   
   return ((dst + etc, lineFormat),
           (" " * (width - baselineSpace - len(dst) - len(etc) + 5), lineFormat),
           ("%-14s" % self.placementLabel, lineFormat))
コード例 #20
0
ファイル: connEntry.py プロジェクト: refnode/arm
 def _getListingEntry(self, width, currentTime, listingType):
   entryType = self.getType()
   
   # Lines are split into the following components in reverse:
   # init gap - " "
   # content  - "<src>  -->  <dst>     <etc>     "
   # time     - "<uptime>"
   # preType  - " ("
   # category - "<type>"
   # postType - ")   "
   
   lineFormat = uiTools.getColor(CATEGORY_COLOR[entryType])
   timeWidth = 6 if CONFIG["features.connection.markInitialConnections"] else 5
   
   drawEntry = [(" ", lineFormat),
                (self._getListingContent(width - (12 + timeWidth) - 1, listingType), lineFormat),
                (" " * timeWidth, lineFormat),
                (" (", lineFormat),
                (entryType.upper(), lineFormat | curses.A_BOLD),
                (")" + " " * (9 - len(entryType)), lineFormat)]
   return drawEntry
コード例 #21
0
    def _getListingEntry(self, width, currentTime, listingType):
        entryType = self.getType()

        # Lines are split into the following components in reverse:
        # init gap - " "
        # content  - "<src>  -->  <dst>     <etc>     "
        # time     - "<uptime>"
        # preType  - " ("
        # category - "<type>"
        # postType - ")   "

        lineFormat = uiTools.getColor(CATEGORY_COLOR[entryType])
        timeWidth = 6 if CONFIG[
            "features.connection.markInitialConnections"] else 5

        drawEntry = [(" ", lineFormat),
                     (self._getListingContent(width - (12 + timeWidth) - 1,
                                              listingType), lineFormat),
                     (" " * timeWidth, lineFormat), (" (", lineFormat),
                     (entryType.upper(), lineFormat | curses.A_BOLD),
                     (")" + " " * (9 - len(entryType)), lineFormat)]
        return drawEntry
コード例 #22
0
def getFormat(formatAttr):
  """
  Provides the curses drawing attributes for torInterpretor formats.
  
  Arguments:
    formatAttr - list of formatting attributes
  """
  
  # initializes formats if they haven't yet been loaded
  if not FORMATS:
    for colorEnum in torInterpretor.Color.values():
      FORMATS[colorEnum] = uiTools.getColor(colorEnum.lower())
    
    FORMATS[torInterpretor.Attr.BOLD] = curses.A_BOLD
    FORMATS[torInterpretor.Attr.UNDERLINE] = curses.A_UNDERLINE
    FORMATS[torInterpretor.Attr.HILIGHT] = curses.A_STANDOUT
  
  cursesFormatting = curses.A_NORMAL
  
  for attr in formatAttr:
    cursesFormatting |= FORMATS.get(attr, curses.A_NORMAL)
  
  return cursesFormatting
コード例 #23
0
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()
コード例 #24
0
ファイル: wizard.py プロジェクト: fhawah12345/fhawah12345.mra
def showConfirmationDialog(torrcContents, torrcLocation):
    """
  Shows a confirmation dialog with the given torrc contents, returning CANCEL,
  NEXT, or BACK based on the selection.
  
  Arguments:
    torrcContents - lines of torrc contents to be presented
    torrcLocation - path where the torrc will be placed
  """

    torrcLines = torrcContents.split("\n")
    options = ["Cancel", "Back to Setup", "Start Tor"]

    control = cli.controller.getController()
    screenHeight = control.getScreen().getmaxyx()[0]
    stickyHeight = sum(
        [stickyPanel.getHeight() for stickyPanel in control.getStickyPanels()])
    isScrollbarVisible = len(torrcLines) + stickyHeight + 5 > screenHeight

    xOffset = 3 if isScrollbarVisible else 0
    popup, width, height = cli.popups.init(len(torrcLines) + 5, 84 + xOffset)
    if not popup: return False

    try:
        scroll, selection = 0, 2
        curses.cbreak()

        while True:
            popup.win.erase()
            popup.win.box()

            # renders the scrollbar
            if isScrollbarVisible:
                popup.addScrollBar(scroll, scroll + height - 5,
                                   len(torrcLines), 1, height - 4, 1)

            # shows the path where the torrc will be placed
            titleMsg = "The following will be placed at '%s':" % torrcLocation
            popup.addstr(0, 0, titleMsg, curses.A_STANDOUT)

            # renders the torrc contents
            for i in range(scroll, min(len(torrcLines), height - 5 + scroll)):
                # parses the argument and comment from options
                option, arg, comment = uiTools.cropStr(torrcLines[i], width -
                                                       4 - xOffset), "", ""

                div = option.find("#")
                if div != -1: option, comment = option[:div], option[div:]

                div = option.strip().find(" ")
                if div != -1: option, arg = option[:div], option[div:]

                drawX = 2 + xOffset
                popup.addstr(i + 1 - scroll, drawX, option,
                             curses.A_BOLD | uiTools.getColor("green"))
                drawX += len(option)
                popup.addstr(i + 1 - scroll, drawX, arg,
                             curses.A_BOLD | uiTools.getColor("cyan"))
                drawX += len(arg)
                popup.addstr(i + 1 - scroll, drawX, comment,
                             uiTools.getColor("white"))

            # divider between the torrc and the options
            popup.addch(height - 4, 0, curses.ACS_LTEE)
            popup.addch(height - 4, width, curses.ACS_RTEE)
            popup.hline(height - 4, 1, width - 1)
            if isScrollbarVisible: popup.addch(height - 4, 2, curses.ACS_BTEE)

            # renders the selection options
            confirmationMsg = "Run tor with the above configuration?"
            popup.addstr(height - 3, width - len(confirmationMsg) - 1,
                         confirmationMsg,
                         uiTools.getColor("green") | curses.A_BOLD)

            drawX = width - 1
            for i in range(len(options) - 1, -1, -1):
                optionLabel = " %s " % options[i]
                drawX -= (len(optionLabel) + 4)

                selectionFormat = curses.A_STANDOUT if i == selection else curses.A_NORMAL
                popup.addstr(height - 2, drawX, "[", uiTools.getColor("green"))
                popup.addstr(
                    height - 2, drawX + 1, optionLabel,
                    uiTools.getColor("green") | selectionFormat
                    | curses.A_BOLD)
                popup.addstr(height - 2, drawX + len(optionLabel) + 1, "]",
                             uiTools.getColor("green"))

                drawX -= 1  # space gap between the options

            popup.win.refresh()
            key = cli.controller.getController().getScreen().getch()

            if key == curses.KEY_LEFT:
                selection = (selection - 1) % len(options)
            elif key == curses.KEY_RIGHT:
                selection = (selection + 1) % len(options)
            elif uiTools.isScrollKey(key):
                scroll = uiTools.getScrollPosition(key, scroll, height - 5,
                                                   len(torrcLines))
            elif uiTools.isSelectionKey(key):
                if selection == 0: return CANCEL
                elif selection == 1: return BACK
                else: return NEXT
            elif key in (27, ord('q'), ord('Q')): return CANCEL
    finally:
        cli.popups.finalize()
コード例 #25
0
ファイル: wizard.py プロジェクト: fhawah12345/fhawah12345.mra
def promptRelayType(initialSelection):
    """
  Provides a prompt for selecting the general role we'd like Tor to run with.
  This returns a RelayType enumeration for the selection, or CANCEL if the
  dialog was canceled.
  """

    options = [ConfigOption(opt, "role", opt) for opt in RelayType.values()]
    options.append(ConfigOption(CANCEL, "general", CANCEL))
    selection = RelayType.indexOf(initialSelection)
    height = 28

    # drops the resume option if it isn't applicable
    control = cli.controller.getController()
    if not control.getTorManager().isTorrcAvailable():
        options.pop(0)
        height -= 3
        selection -= 1

    popup, _, _ = cli.popups.init(height, 58)
    if not popup: return

    try:
        popup.win.box()
        curses.cbreak()

        # provides the welcoming message
        topContent = _splitStr(CONFIG["wizard.message.role"], 54)
        for i in range(len(topContent)):
            popup.addstr(i + 1, 2, topContent[i],
                         curses.A_BOLD | uiTools.getColor(MSG_COLOR))

        while True:
            y, offset = len(topContent) + 1, 0

            for opt in options:
                optionFormat = uiTools.getColor(MSG_COLOR)
                if opt == options[selection]: optionFormat |= curses.A_STANDOUT

                # Curses has a weird bug where there's a one-pixel alignment
                # difference between bold and regular text, so it looks better
                # to render the whitespace here as not being bold.

                offset += 1
                label = opt.getLabel(" ")
                popup.addstr(y + offset, 2, label,
                             optionFormat | curses.A_BOLD)
                popup.addstr(y + offset, 2 + len(label),
                             " " * (54 - len(label)), optionFormat)
                offset += 1

                for line in opt.getDescription(52, " "):
                    popup.addstr(y + offset, 2, uiTools.padStr(line, 54),
                                 optionFormat)
                    offset += 1

            popup.win.refresh()
            key = control.getScreen().getch()

            if key == curses.KEY_UP: selection = (selection - 1) % len(options)
            elif key == curses.KEY_DOWN:
                selection = (selection + 1) % len(options)
            elif uiTools.isSelectionKey(key):
                return options[selection].getValue()
            elif key in (27, ord('q'), ord('Q')):
                return CANCEL  # esc or q - cancel
    finally:
        cli.popups.finalize()
コード例 #26
0
ファイル: logPanel.py プロジェクト: zhou-kz/arm
    def draw(self, subwindow, width, height):
        """
    Redraws message log. Entries stretch to use available space and may
    contain up to two lines. Starts with newest entries.
    """

        self.valsLock.acquire()
        self._lastLoggedEvents, self._lastUpdate = list(
            self.msgLog), time.time()

        # draws the top label
        self.addstr(0, 0, self._getTitle(width), curses.A_STANDOUT)

        # restricts scroll location to valid bounds
        self.scroll = max(
            0, min(self.scroll, self.lastContentHeight - height + 1))

        # draws left-hand scroll bar if content's longer than the height
        msgIndent, dividerIndent = 0, 0  # offsets for scroll bar
        isScrollBarVisible = self.lastContentHeight > height - 1
        if isScrollBarVisible:
            msgIndent, dividerIndent = 3, 2
            self.addScrollBar(self.scroll, self.scroll + height - 1,
                              self.lastContentHeight, 1)

        # draws log entries
        lineCount = 1 - self.scroll
        seenFirstDateDivider = False
        dividerAttr, duplicateAttr = curses.A_BOLD | uiTools.getColor(
            "yellow"), curses.A_BOLD | uiTools.getColor("green")

        isDatesShown = self.regexFilter == None and self._config[
            "features.log.showDateDividers"]
        eventLog = getDaybreaks(
            self.msgLog, self._isPaused) if isDatesShown else list(self.msgLog)
        if not self.showDuplicates:
            deduplicatedLog = getDuplicates(eventLog)

            if deduplicatedLog == None:
                msg = "Deduplication took too long. Its current implementation has difficulty handling large logs so disabling it to keep the interface responsive."
                log.log(log.WARN, msg)
                self.showDuplicates = True
                deduplicatedLog = [(entry, 0) for entry in eventLog]
        else:
            deduplicatedLog = [(entry, 0) for entry in eventLog]

        # determines if we have the minimum width to show date dividers
        showDaybreaks = width - dividerIndent >= 3

        while deduplicatedLog:
            entry, duplicateCount = deduplicatedLog.pop(0)

            if self.regexFilter and not self.regexFilter.search(
                    entry.getDisplayMessage()):
                continue  # filter doesn't match log message - skip

            # checks if we should be showing a divider with the date
            if entry.type == DAYBREAK_EVENT:
                # bottom of the divider
                if seenFirstDateDivider:
                    if lineCount >= 1 and lineCount < height and showDaybreaks:
                        self.win.vline(lineCount, dividerIndent,
                                       curses.ACS_LLCORNER | dividerAttr, 1)
                        self.win.hline(lineCount, dividerIndent + 1,
                                       curses.ACS_HLINE | dividerAttr,
                                       width - dividerIndent - 1)
                        self.win.vline(lineCount, width,
                                       curses.ACS_LRCORNER | dividerAttr, 1)

                    lineCount += 1

                # top of the divider
                if lineCount >= 1 and lineCount < height and showDaybreaks:
                    timeLabel = time.strftime(" %B %d, %Y ",
                                              time.localtime(entry.timestamp))
                    self.win.vline(lineCount, dividerIndent,
                                   curses.ACS_ULCORNER | dividerAttr, 1)
                    self.win.hline(lineCount, dividerIndent + 1,
                                   curses.ACS_HLINE | dividerAttr, 1)
                    self.addstr(lineCount, dividerIndent + 2, timeLabel,
                                curses.A_BOLD | dividerAttr)

                    if dividerIndent + len(timeLabel) + 2 <= width:
                        lineLength = width - dividerIndent - len(timeLabel) - 2
                        self.win.hline(lineCount,
                                       dividerIndent + len(timeLabel) + 2,
                                       curses.ACS_HLINE | dividerAttr,
                                       lineLength)
                        self.win.vline(
                            lineCount,
                            dividerIndent + len(timeLabel) + 2 + lineLength,
                            curses.ACS_URCORNER | dividerAttr, 1)

                seenFirstDateDivider = True
                lineCount += 1
            else:
                # entry contents to be displayed, tuples of the form:
                # (msg, formatting, includeLinebreak)
                displayQueue = []

                msgComp = entry.getDisplayMessage().split("\n")
                for i in range(len(msgComp)):
                    font = curses.A_BOLD if "ERR" in entry.type else curses.A_NORMAL  # emphasizes ERR messages
                    displayQueue.append((msgComp[i].strip(),
                                         font | uiTools.getColor(entry.color),
                                         i != len(msgComp) - 1))

                if duplicateCount:
                    pluralLabel = "s" if duplicateCount > 1 else ""
                    duplicateMsg = DUPLICATE_MSG % (duplicateCount,
                                                    pluralLabel)
                    displayQueue.append((duplicateMsg, duplicateAttr, False))

                cursorLoc, lineOffset = msgIndent, 0
                maxEntriesPerLine = self._config[
                    "features.log.maxLinesPerEntry"]
                while displayQueue:
                    msg, format, includeBreak = displayQueue.pop(0)
                    drawLine = lineCount + lineOffset
                    if lineOffset == maxEntriesPerLine: break

                    maxMsgSize = width - cursorLoc
                    if len(msg) > maxMsgSize:
                        # message is too long - break it up
                        if lineOffset == maxEntriesPerLine - 1:
                            msg = uiTools.cropStr(msg, maxMsgSize)
                        else:
                            msg, remainder = uiTools.cropStr(
                                msg, maxMsgSize, 4, 4, uiTools.END_WITH_HYPHEN,
                                True)
                            displayQueue.insert(
                                0, (remainder.strip(), format, includeBreak))

                        includeBreak = True

                    if drawLine < height and drawLine >= 1:
                        if seenFirstDateDivider and width - dividerIndent >= 3 and showDaybreaks:
                            self.win.vline(drawLine, dividerIndent,
                                           curses.ACS_VLINE | dividerAttr, 1)
                            self.win.vline(drawLine, width,
                                           curses.ACS_VLINE | dividerAttr, 1)

                        self.addstr(drawLine, cursorLoc, msg, format)

                    cursorLoc += len(msg)

                    if includeBreak or not displayQueue:
                        lineOffset += 1
                        cursorLoc = msgIndent + ENTRY_INDENT

                lineCount += lineOffset

            # if this is the last line and there's room, then draw the bottom of the divider
            if not deduplicatedLog and seenFirstDateDivider:
                if lineCount < height and showDaybreaks:
                    # when resizing with a small width the following entries can be
                    # problematc (though I'm not sure why)
                    try:
                        self.win.vline(lineCount, dividerIndent,
                                       curses.ACS_LLCORNER | dividerAttr, 1)
                        self.win.hline(lineCount, dividerIndent + 1,
                                       curses.ACS_HLINE | dividerAttr,
                                       width - dividerIndent - 1)
                        self.win.vline(lineCount, width,
                                       curses.ACS_LRCORNER | dividerAttr, 1)
                    except:
                        pass

                lineCount += 1

        # redraw the display if...
        # - lastContentHeight was off by too much
        # - we're off the bottom of the page
        newContentHeight = lineCount + self.scroll - 1
        contentHeightDelta = abs(self.lastContentHeight - newContentHeight)
        forceRedraw, forceRedrawReason = True, ""

        if contentHeightDelta >= CONTENT_HEIGHT_REDRAW_THRESHOLD:
            forceRedrawReason = "estimate was off by %i" % contentHeightDelta
        elif newContentHeight > height and self.scroll + height - 1 > newContentHeight:
            forceRedrawReason = "scrolled off the bottom of the page"
        elif not isScrollBarVisible and newContentHeight > height - 1:
            forceRedrawReason = "scroll bar wasn't previously visible"
        elif isScrollBarVisible and newContentHeight <= height - 1:
            forceRedrawReason = "scroll bar shouldn't be visible"
        else:
            forceRedraw = False

        self.lastContentHeight = newContentHeight
        if forceRedraw:
            forceRedrawReason = "redrawing the log panel with the corrected content height (%s)" % forceRedrawReason
            log.log(self._config["log.logPanel.forceDoubleRedraw"],
                    forceRedrawReason)
            self.redraw(True)

        self.valsLock.release()
コード例 #27
0
ファイル: graphPanel.py プロジェクト: zhou-kz/arm
    def draw(self, subwindow, width, height):
        """ Redraws graph panel """

        if self.currentDisplay:
            param = self.stats[self.currentDisplay]
            graphCol = min((width - 10) / 2, param.maxCol)

            primaryColor = uiTools.getColor(param.getColor(True))
            secondaryColor = uiTools.getColor(param.getColor(False))

            if self.showLabel:
                self.addstr(0, 0, param.getTitle(width), curses.A_STANDOUT)

            # top labels
            left, right = param.getHeaderLabel(width / 2,
                                               True), param.getHeaderLabel(
                                                   width / 2, False)
            if left: self.addstr(1, 0, left, curses.A_BOLD | primaryColor)
            if right:
                self.addstr(1, graphCol + 5, right,
                            curses.A_BOLD | secondaryColor)

            # determines max/min value on the graph
            if self.bounds == BOUNDS_GLOBAL_MAX:
                primaryMaxBound = int(param.maxPrimary[self.updateInterval])
                secondaryMaxBound = int(
                    param.maxSecondary[self.updateInterval])
            else:
                # both BOUNDS_LOCAL_MAX and BOUNDS_TIGHT use local maxima
                if graphCol < 2:
                    # nothing being displayed
                    primaryMaxBound, secondaryMaxBound = 0, 0
                else:
                    primaryMaxBound = int(
                        max(param.primaryCounts[self.updateInterval]
                            [1:graphCol + 1]))
                    secondaryMaxBound = int(
                        max(param.secondaryCounts[self.updateInterval]
                            [1:graphCol + 1]))

            primaryMinBound = secondaryMinBound = 0
            if self.bounds == BOUNDS_TIGHT:
                primaryMinBound = int(
                    min(param.primaryCounts[self.updateInterval][1:graphCol +
                                                                 1]))
                secondaryMinBound = int(
                    min(param.secondaryCounts[self.updateInterval][1:graphCol +
                                                                   1]))

                # if the max = min (ie, all values are the same) then use zero lower
                # bound so a graph is still displayed
                if primaryMinBound == primaryMaxBound: primaryMinBound = 0
                if secondaryMinBound == secondaryMaxBound:
                    secondaryMinBound = 0

            # displays upper and lower bounds
            self.addstr(2, 0, "%4i" % primaryMaxBound, primaryColor)
            self.addstr(self.graphHeight + 1, 0, "%4i" % primaryMinBound,
                        primaryColor)

            self.addstr(2, graphCol + 5, "%4i" % secondaryMaxBound,
                        secondaryColor)
            self.addstr(self.graphHeight + 1, graphCol + 5,
                        "%4i" % secondaryMinBound, secondaryColor)

            # displays intermediate bounds on every other row
            if CONFIG["features.graph.showIntermediateBounds"]:
                ticks = (self.graphHeight - 3) / 2
                for i in range(ticks):
                    row = self.graphHeight - (2 * i) - 3
                    if self.graphHeight % 2 == 0 and i >= (ticks / 2): row -= 1

                    if primaryMinBound != primaryMaxBound:
                        primaryVal = (primaryMaxBound - primaryMinBound) / (
                            self.graphHeight - 1) * (self.graphHeight - row -
                                                     1)
                        if not primaryVal in (primaryMinBound,
                                              primaryMaxBound):
                            self.addstr(row + 2, 0, "%4i" % primaryVal,
                                        primaryColor)

                    if secondaryMinBound != secondaryMaxBound:
                        secondaryVal = (secondaryMaxBound - secondaryMinBound
                                        ) / (self.graphHeight -
                                             1) * (self.graphHeight - row - 1)
                        if not secondaryVal in (secondaryMinBound,
                                                secondaryMaxBound):
                            self.addstr(row + 2, graphCol + 5,
                                        "%4i" % secondaryVal, secondaryColor)

            # creates bar graph (both primary and secondary)
            for col in range(graphCol):
                colCount = int(param.primaryCounts[self.updateInterval][
                    col + 1]) - primaryMinBound
                colHeight = min(
                    self.graphHeight, self.graphHeight * colCount /
                    (max(1, primaryMaxBound) - primaryMinBound))
                for row in range(colHeight):
                    self.addstr(self.graphHeight + 1 - row, col + 5, " ",
                                curses.A_STANDOUT | primaryColor)

                colCount = int(param.secondaryCounts[self.updateInterval][
                    col + 1]) - secondaryMinBound
                colHeight = min(
                    self.graphHeight, self.graphHeight * colCount /
                    (max(1, secondaryMaxBound) - secondaryMinBound))
                for row in range(colHeight):
                    self.addstr(self.graphHeight + 1 - row,
                                col + graphCol + 10, " ",
                                curses.A_STANDOUT | secondaryColor)

            # bottom labeling of x-axis
            intervalSec = 1  # seconds per labeling
            for i in range(len(UPDATE_INTERVALS)):
                if i == self.updateInterval:
                    intervalSec = UPDATE_INTERVALS[i][1]

            intervalSpacing = 10 if graphCol >= WIDE_LABELING_GRAPH_COL else 5
            unitsLabel, decimalPrecision = None, 0
            for i in range((graphCol - 4) / intervalSpacing):
                loc = (i + 1) * intervalSpacing
                timeLabel = uiTools.getTimeLabel(loc * intervalSec,
                                                 decimalPrecision)

                if not unitsLabel: unitsLabel = timeLabel[-1]
                elif unitsLabel != timeLabel[-1]:
                    # upped scale so also up precision of future measurements
                    unitsLabel = timeLabel[-1]
                    decimalPrecision += 1
                else:
                    # if constrained on space then strips labeling since already provided
                    timeLabel = timeLabel[:-1]

                self.addstr(self.graphHeight + 2, 4 + loc, timeLabel,
                            primaryColor)
                self.addstr(self.graphHeight + 2, graphCol + 10 + loc,
                            timeLabel, secondaryColor)

            param.draw(self, width,
                       height)  # allows current stats to modify the display
コード例 #28
0
ファイル: configPanel.py プロジェクト: katmagic/arm
 def _drawSelectionPanel(self, cursorSelection, width, detailPanelHeight, titleLabel):
   """
   Renders a panel for the selected configuration option.
   """
   
   # border (top)
   if width >= len(titleLabel):
     self.win.hline(0, len(titleLabel), curses.ACS_HLINE, width - len(titleLabel))
     self.win.addch(0, width, curses.ACS_URCORNER)
   
   # border (sides)
   self.win.vline(1, 0, curses.ACS_VLINE, detailPanelHeight - 1)
   self.win.vline(1, width, curses.ACS_VLINE, detailPanelHeight - 1)
   
   # border (bottom)
   self.win.addch(detailPanelHeight, 0, curses.ACS_LLCORNER)
   if width >= 2: self.win.addch(detailPanelHeight, 1, curses.ACS_TTEE)
   if width >= 3: self.win.hline(detailPanelHeight, 2, curses.ACS_HLINE, width - 2)
   self.win.addch(detailPanelHeight, width, curses.ACS_LRCORNER)
   
   selectionFormat = curses.A_BOLD | uiTools.getColor(CATEGORY_COLOR[cursorSelection.get(FIELD_CATEGORY)])
   
   # first entry:
   # <option> (<category> Option)
   optionLabel =" (%s Option)" % torConfig.OPTION_CATEGORY_STR[cursorSelection.get(FIELD_CATEGORY)]
   self.addstr(1, 2, cursorSelection.get(FIELD_OPTION) + optionLabel, selectionFormat)
   
   # second entry:
   # Value: <value> ([default|custom], <type>, usage: <argument usage>)
   if detailPanelHeight >= 3:
     valueAttr = []
     valueAttr.append("default" if cursorSelection.get(FIELD_IS_DEFAULT) else "custom")
     valueAttr.append(cursorSelection.get(FIELD_TYPE))
     valueAttr.append("usage: %s" % (cursorSelection.get(FIELD_ARG_USAGE)))
     valueAttrLabel = ", ".join(valueAttr)
     
     valueLabelWidth = width - 12 - len(valueAttrLabel)
     valueLabel = uiTools.cropStr(cursorSelection.get(FIELD_VALUE), valueLabelWidth)
     
     self.addstr(2, 2, "Value: %s (%s)" % (valueLabel, valueAttrLabel), selectionFormat)
   
   # remainder is filled with the man page description
   descriptionHeight = max(0, detailPanelHeight - 3)
   descriptionContent = "Description: " + cursorSelection.get(FIELD_DESCRIPTION)
   
   for i in range(descriptionHeight):
     # checks if we're done writing the description
     if not descriptionContent: break
     
     # there's a leading indent after the first line
     if i > 0: descriptionContent = "  " + descriptionContent
     
     # we only want to work with content up until the next newline
     if "\n" in descriptionContent:
       lineContent, descriptionContent = descriptionContent.split("\n", 1)
     else: lineContent, descriptionContent = descriptionContent, ""
     
     if i != descriptionHeight - 1:
       # there's more lines to display
       msg, remainder = uiTools.cropStr(lineContent, width - 2, 4, 4, uiTools.END_WITH_HYPHEN, True)
       descriptionContent = remainder.strip() + descriptionContent
     else:
       # this is the last line, end it with an ellipse
       msg = uiTools.cropStr(lineContent, width - 2, 4, 4)
     
     self.addstr(3 + i, 2, msg, selectionFormat)
コード例 #29
0
ファイル: descriptorPopup.py プロジェクト: lnrsoft/arm
def draw(popup, fingerprint, displayText, displayColor, scroll,
         showLineNumber):
    popup.win.erase()
    popup.win.box()
    xOffset = 2

    if fingerprint: title = "Consensus Descriptor (%s):" % fingerprint
    else: title = "Consensus Descriptor:"
    popup.addstr(0, 0, title, curses.A_STANDOUT)

    lineNumWidth = int(math.log10(len(displayText))) + 1
    isEncryptionBlock = False  # flag indicating if we're currently displaying a key

    # checks if first line is in an encryption block
    for i in range(0, scroll):
        lineText = displayText[i].strip()
        if lineText in SIG_START_KEYS: isEncryptionBlock = True
        elif lineText in SIG_END_KEYS: isEncryptionBlock = False

    drawLine, pageHeight = 1, popup.maxY - 2
    for i in range(scroll, scroll + pageHeight):
        lineText = displayText[i].strip()
        xOffset = 2

        if showLineNumber:
            lineNumLabel = ("%%%ii" % lineNumWidth) % (i + 1)
            lineNumFormat = curses.A_BOLD | uiTools.getColor(LINE_NUM_COLOR)

            popup.addstr(drawLine, xOffset, lineNumLabel, lineNumFormat)
            xOffset += lineNumWidth + 1

        # Most consensus and descriptor lines are keyword/value pairs. Both are
        # shown with the same color, but the keyword is bolded.

        keyword, value = lineText, ""
        drawFormat = uiTools.getColor(displayColor)

        if lineText.startswith(HEADER_PREFIX[0]) or lineText.startswith(
                HEADER_PREFIX[1]):
            keyword, value = lineText, ""
            drawFormat = uiTools.getColor(HEADER_COLOR)
        elif lineText == UNRESOLVED_MSG or lineText == ERROR_MSG:
            keyword, value = lineText, ""
        elif lineText in SIG_START_KEYS:
            keyword, value = lineText, ""
            isEncryptionBlock = True
            drawFormat = uiTools.getColor(SIG_COLOR)
        elif lineText in SIG_END_KEYS:
            keyword, value = lineText, ""
            isEncryptionBlock = False
            drawFormat = uiTools.getColor(SIG_COLOR)
        elif isEncryptionBlock:
            keyword, value = "", lineText
            drawFormat = uiTools.getColor(SIG_COLOR)
        elif " " in lineText:
            divIndex = lineText.find(" ")
            keyword, value = lineText[:divIndex], lineText[divIndex:]

        displayQueue = [(keyword, drawFormat | curses.A_BOLD),
                        (value, drawFormat)]
        cursorLoc = xOffset

        while displayQueue:
            msg, format = displayQueue.pop(0)
            if not msg: continue

            maxMsgSize = popup.maxX - 1 - cursorLoc
            if len(msg) >= maxMsgSize:
                # needs to split up the line
                msg, remainder = uiTools.cropStr(msg,
                                                 maxMsgSize,
                                                 None,
                                                 endType=None,
                                                 getRemainder=True)

                if xOffset == cursorLoc and msg == "":
                    # first word is longer than the line
                    msg = uiTools.cropStr(remainder, maxMsgSize)

                    if " " in remainder:
                        remainder = remainder.split(" ", 1)[1]
                    else:
                        remainder = ""

                popup.addstr(drawLine, cursorLoc, msg, format)
                cursorLoc = xOffset

                if remainder:
                    displayQueue.insert(0, (remainder.strip(), format))
                    drawLine += 1
            else:
                popup.addstr(drawLine, cursorLoc, msg, format)
                cursorLoc += len(msg)

            if drawLine > pageHeight: break

        drawLine += 1
        if drawLine > pageHeight: break

    popup.win.refresh()
コード例 #30
0
    def draw(self, width, height):
        self.valsLock.acquire()

        # If true, we assume that the cached value in self._lastContentHeight is
        # still accurate, and stop drawing when there's nothing more to display.
        # Otherwise the self._lastContentHeight is suspect, and we'll process all
        # the content to check if it's right (and redraw again with the corrected
        # height if not).
        trustLastContentHeight = self._lastContentHeightArgs == (width, height)

        # restricts scroll location to valid bounds
        self.scroll = max(
            0, min(self.scroll, self._lastContentHeight - height + 1))

        renderedContents, corrections, confLocation = None, {}, None
        if self.configType == Config.TORRC:
            loadedTorrc = torConfig.getTorrc()
            loadedTorrc.getLock().acquire()
            confLocation = loadedTorrc.getConfigLocation()

            if not loadedTorrc.isLoaded():
                renderedContents = ["### Unable to load the torrc ###"]
            else:
                renderedContents = loadedTorrc.getDisplayContents(
                    self.stripComments)

                # constructs a mapping of line numbers to the issue on it
                corrections = dict(
                    (lineNum, (issue, msg))
                    for lineNum, issue, msg in loadedTorrc.getCorrections())

            loadedTorrc.getLock().release()
        else:
            loadedArmrc = conf.getConfig("arm")
            confLocation = loadedArmrc.path
            renderedContents = list(loadedArmrc.rawContents)

        # offset to make room for the line numbers
        lineNumOffset = 0
        if self.showLineNum:
            if len(renderedContents) == 0: lineNumOffset = 2
            else: lineNumOffset = int(math.log10(len(renderedContents))) + 2

        # draws left-hand scroll bar if content's longer than the height
        scrollOffset = 0
        if self._config[
                "features.config.file.showScrollbars"] and self._lastContentHeight > height - 1:
            scrollOffset = 3
            self.addScrollBar(self.scroll, self.scroll + height - 1,
                              self._lastContentHeight, 1)

        displayLine = -self.scroll + 1  # line we're drawing on

        # draws the top label
        if self.isTitleVisible():
            sourceLabel = "Tor" if self.configType == Config.TORRC else "Arm"
            locationLabel = " (%s)" % confLocation if confLocation else ""
            self.addstr(
                0, 0,
                "%s Configuration File%s:" % (sourceLabel, locationLabel),
                curses.A_STANDOUT)

        isMultiline = False  # true if we're in the middle of a multiline torrc entry
        for lineNumber in range(0, len(renderedContents)):
            lineText = renderedContents[lineNumber]
            lineText = lineText.rstrip()  # remove ending whitespace

            # blank lines are hidden when stripping comments
            if self.stripComments and not lineText: continue

            # splits the line into its component (msg, format) tuples
            lineComp = {
                "option": ["", curses.A_BOLD | uiTools.getColor("green")],
                "argument": ["", curses.A_BOLD | uiTools.getColor("cyan")],
                "correction": ["", curses.A_BOLD | uiTools.getColor("cyan")],
                "comment": ["", uiTools.getColor("white")]
            }

            # parses the comment
            commentIndex = lineText.find("#")
            if commentIndex != -1:
                lineComp["comment"][0] = lineText[commentIndex:]
                lineText = lineText[:commentIndex]

            # splits the option and argument, preserving any whitespace around them
            strippedLine = lineText.strip()
            optionIndex = strippedLine.find(" ")
            if isMultiline:
                # part of a multiline entry started on a previous line so everything
                # is part of the argument
                lineComp["argument"][0] = lineText
            elif optionIndex == -1:
                # no argument provided
                lineComp["option"][0] = lineText
            else:
                optionText = strippedLine[:optionIndex]
                optionEnd = lineText.find(optionText) + len(optionText)
                lineComp["option"][0] = lineText[:optionEnd]
                lineComp["argument"][0] = lineText[optionEnd:]

            # flags following lines as belonging to this multiline entry if it ends
            # with a slash
            if strippedLine: isMultiline = strippedLine.endswith("\\")

            # gets the correction
            if lineNumber in corrections:
                lineIssue, lineIssueMsg = corrections[lineNumber]

                if lineIssue in (torConfig.ValidationError.DUPLICATE,
                                 torConfig.ValidationError.IS_DEFAULT):
                    lineComp["option"][1] = curses.A_BOLD | uiTools.getColor(
                        "blue")
                    lineComp["argument"][1] = curses.A_BOLD | uiTools.getColor(
                        "blue")
                elif lineIssue == torConfig.ValidationError.MISMATCH:
                    lineComp["argument"][1] = curses.A_BOLD | uiTools.getColor(
                        "red")
                    lineComp["correction"][0] = " (%s)" % lineIssueMsg
                else:
                    # For some types of configs the correction field is simply used to
                    # provide extra data (for instance, the type for tor state fields).
                    lineComp["correction"][0] = " (%s)" % lineIssueMsg
                    lineComp["correction"][
                        1] = curses.A_BOLD | uiTools.getColor("magenta")

            # draws the line number
            if self.showLineNum and displayLine < height and displayLine >= 1:
                lineNumStr = ("%%%ii" % (lineNumOffset - 1)) % (lineNumber + 1)
                self.addstr(displayLine, scrollOffset, lineNumStr,
                            curses.A_BOLD | uiTools.getColor("yellow"))

            # draws the rest of the components with line wrap
            cursorLoc, lineOffset = lineNumOffset + scrollOffset, 0
            maxLinesPerEntry = self._config[
                "features.config.file.maxLinesPerEntry"]
            displayQueue = [
                lineComp[entry]
                for entry in ("option", "argument", "correction", "comment")
            ]

            while displayQueue:
                msg, format = displayQueue.pop(0)

                maxMsgSize, includeBreak = width - cursorLoc, False
                if len(msg) >= maxMsgSize:
                    # message is too long - break it up
                    if lineOffset == maxLinesPerEntry - 1:
                        msg = uiTools.cropStr(msg, maxMsgSize)
                    else:
                        includeBreak = True
                        msg, remainder = uiTools.cropStr(
                            msg, maxMsgSize, 4, 4, uiTools.Ending.HYPHEN, True)
                        displayQueue.insert(0, (remainder.strip(), format))

                drawLine = displayLine + lineOffset
                if msg and drawLine < height and drawLine >= 1:
                    self.addstr(drawLine, cursorLoc, msg, format)

                # If we're done, and have added content to this line, then start
                # further content on the next line.
                cursorLoc += len(msg)
                includeBreak |= not displayQueue and cursorLoc != lineNumOffset + scrollOffset

                if includeBreak:
                    lineOffset += 1
                    cursorLoc = lineNumOffset + scrollOffset

            displayLine += max(lineOffset, 1)

            if trustLastContentHeight and displayLine >= height: break

        if not trustLastContentHeight:
            self._lastContentHeightArgs = (width, height)
            newContentHeight = displayLine + self.scroll - 1

            if self._lastContentHeight != newContentHeight:
                self._lastContentHeight = newContentHeight
                self.redraw(True)

        self.valsLock.release()
コード例 #31
0
ファイル: fileDescriptorPopup.py プロジェクト: zhou-kz/arm
def draw(popup, properties):
    popup.clear()
    popup.win.box()

    # top label
    popup.addstr(0, 0, "Open File Descriptors:", curses.A_STANDOUT)

    if properties.errorMsg:
        popup.addstr(1, 2, properties.errorMsg,
                     curses.A_BOLD | uiTools.getColor("red"))
    else:
        # text with file descriptor count and limit
        fdCount = len(properties.fdFile) + len(properties.fdConn) + len(
            properties.fdMisc)
        fdCountPer = 100 * fdCount / max(properties.fdLimit, 1)

        statsColor = "green"
        if fdCountPer >= 90: statsColor = "red"
        elif fdCountPer >= 50: statsColor = "yellow"

        countMsg = "%i / %i (%i%%)" % (fdCount, properties.fdLimit, fdCountPer)
        popup.addstr(1, 2, countMsg,
                     curses.A_BOLD | uiTools.getColor(statsColor))

        # provides a progress bar reflecting the stats
        barWidth = popup.maxX - len(
            countMsg) - 6  # space between "[ ]" in progress bar
        barProgress = barWidth * fdCountPer / 100  # filled cells
        if fdCount > 0:
            barProgress = max(
                1,
                barProgress)  # ensures one cell is filled unless really zero
        popup.addstr(1, len(countMsg) + 3, "[", curses.A_BOLD)
        popup.addstr(1,
                     len(countMsg) + 4, " " * barProgress,
                     curses.A_STANDOUT | uiTools.getColor(statsColor))
        popup.addstr(1, len(countMsg) + 4 + barWidth, "]", curses.A_BOLD)

        popup.win.hline(2, 1, curses.ACS_HLINE, popup.maxX - 2)

        # scrollable file descriptor listing
        lineNum = 3
        entryNum = properties.scroll
        while lineNum <= popup.maxY - 2:
            if entryNum < len(properties.fdFile):
                line = properties.fdFile[entryNum]
                color = "green"
            elif entryNum < len(properties.fdFile) + len(properties.fdMisc):
                line = properties.fdMisc[entryNum - len(properties.fdFile)]
                color = "cyan"
            else:
                line = properties.fdConn[entryNum - len(properties.fdFile) -
                                         len(properties.fdMisc)]
                color = "blue"

            popup.addstr(lineNum, 2, line,
                         curses.A_BOLD | uiTools.getColor(color))
            lineNum += 1
            entryNum += 1

    popup.refresh()
コード例 #32
0
 def showWriteDialog(self):
   """
   Provies an interface to confirm if the configuration is saved and, if so,
   where.
   """
   
   # display a popup for saving the current configuration
   configLines = torConfig.getCustomOptions(True)
   popup, width, height = popups.init(len(configLines) + 2)
   if not popup: return
   
   try:
     # displayed options (truncating the labels if there's limited room)
     if width >= 30: selectionOptions = ("Save", "Save As...", "Cancel")
     else: selectionOptions = ("Save", "Save As", "X")
     
     # checks if we can show options beside the last line of visible content
     isOptionLineSeparate = False
     lastIndex = min(height - 2, len(configLines) - 1)
     
     # if we don't have room to display the selection options and room to
     # grow then display the selection options on its own line
     if width < (30 + len(configLines[lastIndex])):
       popup.setHeight(height + 1)
       popup.redraw(True) # recreates the window instance
       newHeight, _ = popup.getPreferredSize()
       
       if newHeight > height:
         height = newHeight
         isOptionLineSeparate = True
     
     key, selection = 0, 2
     while not uiTools.isSelectionKey(key):
       # if the popup has been resized then recreate it (needed for the
       # proper border height)
       newHeight, newWidth = popup.getPreferredSize()
       if (height, width) != (newHeight, newWidth):
         height, width = newHeight, newWidth
         popup.redraw(True)
       
       # if there isn't room to display the popup then cancel it
       if height <= 2:
         selection = 2
         break
       
       popup.win.erase()
       popup.win.box()
       popup.addstr(0, 0, "Configuration being saved:", curses.A_STANDOUT)
       
       visibleConfigLines = height - 3 if isOptionLineSeparate else height - 2
       for i in range(visibleConfigLines):
         line = uiTools.cropStr(configLines[i], width - 2)
         
         if " " in line:
           option, arg = line.split(" ", 1)
           popup.addstr(i + 1, 1, option, curses.A_BOLD | uiTools.getColor("green"))
           popup.addstr(i + 1, len(option) + 2, arg, curses.A_BOLD | uiTools.getColor("cyan"))
         else:
           popup.addstr(i + 1, 1, line, curses.A_BOLD | uiTools.getColor("green"))
       
       # draws selection options (drawn right to left)
       drawX = width - 1
       for i in range(len(selectionOptions) - 1, -1, -1):
         optionLabel = selectionOptions[i]
         drawX -= (len(optionLabel) + 2)
         
         # if we've run out of room then drop the option (this will only
         # occure on tiny displays)
         if drawX < 1: break
         
         selectionFormat = curses.A_STANDOUT if i == selection else curses.A_NORMAL
         popup.addstr(height - 2, drawX, "[")
         popup.addstr(height - 2, drawX + 1, optionLabel, selectionFormat | curses.A_BOLD)
         popup.addstr(height - 2, drawX + len(optionLabel) + 1, "]")
         
         drawX -= 1 # space gap between the options
       
       popup.win.refresh()
       
       key = cli.controller.getController().getScreen().getch()
       if key == curses.KEY_LEFT: selection = max(0, selection - 1)
       elif key == curses.KEY_RIGHT: selection = min(len(selectionOptions) - 1, selection + 1)
     
     if selection in (0, 1):
       loadedTorrc, promptCanceled = torConfig.getTorrc(), False
       try: configLocation = loadedTorrc.getConfigLocation()
       except IOError: configLocation = ""
       
       if selection == 1:
         # prompts user for a configuration location
         configLocation = popups.inputPrompt("Save to (esc to cancel): ", configLocation)
         if not configLocation: promptCanceled = True
       
       if not promptCanceled:
         try:
           torConfig.saveConf(configLocation, configLines)
           msg = "Saved configuration to %s" % configLocation
         except IOError, exc:
           msg = "Unable to save configuration (%s)" % sysTools.getFileErrorMsg(exc)
         
         popups.showMsg(msg, 2)
   finally: popups.finalize()
コード例 #33
0
ファイル: descriptorPopup.py プロジェクト: JustMe23/arm
def draw(popup, fingerprint, displayText, displayColor, scroll, showLineNumber):
  popup.win.erase()
  popup.win.box()
  xOffset = 2
  
  if fingerprint: title = "Consensus Descriptor (%s):" % fingerprint
  else: title = "Consensus Descriptor:"
  popup.addstr(0, 0, title, curses.A_STANDOUT)
  
  lineNumWidth = int(math.log10(len(displayText))) + 1
  isEncryptionBlock = False   # flag indicating if we're currently displaying a key
  
  # checks if first line is in an encryption block
  for i in range(0, scroll):
    lineText = displayText[i].strip()
    if lineText in SIG_START_KEYS: isEncryptionBlock = True
    elif lineText in SIG_END_KEYS: isEncryptionBlock = False
  
  drawLine, pageHeight = 1, popup.maxY - 2
  for i in range(scroll, scroll + pageHeight):
    lineText = displayText[i].strip()
    xOffset = 2
    
    if showLineNumber:
      lineNumLabel = ("%%%ii" % lineNumWidth) % (i + 1)
      lineNumFormat = curses.A_BOLD | uiTools.getColor(LINE_NUM_COLOR)
      
      popup.addstr(drawLine, xOffset, lineNumLabel, lineNumFormat)
      xOffset += lineNumWidth + 1
    
    # Most consensus and descriptor lines are keyword/value pairs. Both are
    # shown with the same color, but the keyword is bolded.
    
    keyword, value = lineText, ""
    drawFormat = uiTools.getColor(displayColor)
    
    if lineText.startswith(HEADER_PREFIX[0]) or lineText.startswith(HEADER_PREFIX[1]):
      keyword, value = lineText, ""
      drawFormat = uiTools.getColor(HEADER_COLOR)
    elif lineText == UNRESOLVED_MSG or lineText == ERROR_MSG:
      keyword, value = lineText, ""
    elif lineText in SIG_START_KEYS:
      keyword, value = lineText, ""
      isEncryptionBlock = True
      drawFormat = uiTools.getColor(SIG_COLOR)
    elif lineText in SIG_END_KEYS:
      keyword, value = lineText, ""
      isEncryptionBlock = False
      drawFormat = uiTools.getColor(SIG_COLOR)
    elif isEncryptionBlock:
      keyword, value = "", lineText
      drawFormat = uiTools.getColor(SIG_COLOR)
    elif " " in lineText:
      divIndex = lineText.find(" ")
      keyword, value = lineText[:divIndex], lineText[divIndex:]
    
    displayQueue = [(keyword, drawFormat | curses.A_BOLD), (value, drawFormat)]
    cursorLoc = xOffset
    
    while displayQueue:
      msg, format = displayQueue.pop(0)
      if not msg: continue
      
      maxMsgSize = popup.maxX - 1 - cursorLoc
      if len(msg) >= maxMsgSize:
        # needs to split up the line
        msg, remainder = uiTools.cropStr(msg, maxMsgSize, None, endType = None, getRemainder = True)
        
        if xOffset == cursorLoc and msg == "":
          # first word is longer than the line
          msg = uiTools.cropStr(remainder, maxMsgSize)
          
          if " " in remainder:
            remainder = remainder.split(" ", 1)[1]
          else: remainder = ""
        
        popup.addstr(drawLine, cursorLoc, msg, format)
        cursorLoc = xOffset
        
        if remainder:
          displayQueue.insert(0, (remainder.strip(), format))
          drawLine += 1
      else:
        popup.addstr(drawLine, cursorLoc, msg, format)
        cursorLoc += len(msg)
      
      if drawLine > pageHeight: break
    
    drawLine += 1
    if drawLine > pageHeight: break
  
  popup.win.refresh()
コード例 #34
0
    def _drawSelectionPanel(self, cursorSelection, width, detailPanelHeight,
                            titleLabel):
        """
    Renders a panel for the selected configuration option.
    """

        # border (top)
        if width >= len(titleLabel):
            self.win.hline(0, len(titleLabel), curses.ACS_HLINE,
                           width - len(titleLabel))
            self.win.addch(0, width, curses.ACS_URCORNER)

        # border (sides)
        self.win.vline(1, 0, curses.ACS_VLINE, detailPanelHeight - 1)
        self.win.vline(1, width, curses.ACS_VLINE, detailPanelHeight - 1)

        # border (bottom)
        self.win.addch(detailPanelHeight, 0, curses.ACS_LLCORNER)
        if width >= 2: self.win.addch(detailPanelHeight, 1, curses.ACS_TTEE)
        if width >= 3:
            self.win.hline(detailPanelHeight, 2, curses.ACS_HLINE, width - 2)
        self.win.addch(detailPanelHeight, width, curses.ACS_LRCORNER)

        selectionFormat = curses.A_BOLD | uiTools.getColor(
            CATEGORY_COLOR[cursorSelection.get(FIELD_CATEGORY)])

        # first entry:
        # <option> (<category> Option)
        optionLabel = " (%s Option)" % torConfig.OPTION_CATEGORY_STR[
            cursorSelection.get(FIELD_CATEGORY)]
        self.addstr(1, 2,
                    cursorSelection.get(FIELD_OPTION) + optionLabel,
                    selectionFormat)

        # second entry:
        # Value: <value> ([default|custom], <type>, usage: <argument usage>)
        if detailPanelHeight >= 3:
            valueAttr = []
            valueAttr.append("default" if cursorSelection.get(FIELD_IS_DEFAULT
                                                              ) else "custom")
            valueAttr.append(cursorSelection.get(FIELD_TYPE))
            valueAttr.append("usage: %s" %
                             (cursorSelection.get(FIELD_ARG_USAGE)))
            valueAttrLabel = ", ".join(valueAttr)

            valueLabelWidth = width - 12 - len(valueAttrLabel)
            valueLabel = uiTools.cropStr(cursorSelection.get(FIELD_VALUE),
                                         valueLabelWidth)

            self.addstr(2, 2, "Value: %s (%s)" % (valueLabel, valueAttrLabel),
                        selectionFormat)

        # remainder is filled with the man page description
        descriptionHeight = max(0, detailPanelHeight - 3)
        descriptionContent = "Description: " + cursorSelection.get(
            FIELD_DESCRIPTION)

        for i in range(descriptionHeight):
            # checks if we're done writing the description
            if not descriptionContent: break

            # there's a leading indent after the first line
            if i > 0: descriptionContent = "  " + descriptionContent

            # we only want to work with content up until the next newline
            if "\n" in descriptionContent:
                lineContent, descriptionContent = descriptionContent.split(
                    "\n", 1)
            else:
                lineContent, descriptionContent = descriptionContent, ""

            if i != descriptionHeight - 1:
                # there's more lines to display
                msg, remainder = uiTools.cropStr(lineContent, width - 2, 4, 4,
                                                 uiTools.END_WITH_HYPHEN, True)
                descriptionContent = remainder.strip() + descriptionContent
            else:
                # this is the last line, end it with an ellipse
                msg = uiTools.cropStr(lineContent, width - 2, 4, 4)

            self.addstr(3 + i, 2, msg, selectionFormat)
コード例 #35
0
    def draw(self, subwindow, width, height):
        self.valsLock.acquire()

        # draws the top label
        titleLabel = "%s Configuration:" % ("Tor" if self.configType
                                            == TOR_STATE else "Arm")
        self.addstr(0, 0, titleLabel, curses.A_STANDOUT)

        # panel with details for the current selection
        detailPanelHeight = self._config[
            "features.config.selectionDetails.height"]
        if detailPanelHeight == 0 or detailPanelHeight + 2 >= height:
            # no detail panel
            detailPanelHeight = 0
            scrollLoc = self.scroller.getScrollLoc(self.confContents,
                                                   height - 1)
            cursorSelection = self.getSelection()
        else:
            # Shrink detail panel if there isn't sufficient room for the whole
            # thing. The extra line is for the bottom border.
            detailPanelHeight = min(height - 1, detailPanelHeight + 1)
            scrollLoc = self.scroller.getScrollLoc(
                self.confContents, height - 1 - detailPanelHeight)
            cursorSelection = self.getSelection()

            self._drawSelectionPanel(cursorSelection, width, detailPanelHeight,
                                     titleLabel)

        # draws left-hand scroll bar if content's longer than the height
        scrollOffset = 0
        if len(self.confContents) > height - detailPanelHeight - 1:
            scrollOffset = 3
            self.addScrollBar(scrollLoc,
                              scrollLoc + height - detailPanelHeight - 1,
                              len(self.confContents), 1 + detailPanelHeight)

        optionWidth = self._config["features.config.state.colWidth.option"]
        valueWidth = self._config["features.config.state.colWidth.value"]
        descriptionWidth = max(
            0, width - scrollOffset - optionWidth - valueWidth - 2)

        for lineNum in range(scrollLoc, len(self.confContents)):
            entry = self.confContents[lineNum]
            drawLine = lineNum + detailPanelHeight + 1 - scrollLoc

            optionLabel = uiTools.cropStr(entry.get(FIELD_OPTION), optionWidth)
            valueLabel = uiTools.cropStr(entry.get(FIELD_VALUE), valueWidth)

            # ends description at the first newline
            descriptionLabel = uiTools.cropStr(
                entry.get(FIELD_DESCRIPTION).split("\n")[0], descriptionWidth,
                None)

            lineFormat = curses.A_NORMAL if entry.get(
                FIELD_IS_DEFAULT) else curses.A_BOLD
            if entry.get(FIELD_CATEGORY):
                lineFormat |= uiTools.getColor(
                    CATEGORY_COLOR[entry.get(FIELD_CATEGORY)])
            if entry == cursorSelection: lineFormat |= curses.A_STANDOUT

            lineTextLayout = "%%-%is %%-%is %%-%is" % (optionWidth, valueWidth,
                                                       descriptionWidth)
            lineText = lineTextLayout % (optionLabel, valueLabel,
                                         descriptionLabel)
            self.addstr(drawLine, scrollOffset, lineText, lineFormat)

            if drawLine >= height: break

        self.valsLock.release()
コード例 #36
0
def draw(popup, properties):
    popup.clear()
    popup.win.box()
    xOffset = 2

    if properties.text:
        if properties.fingerprint:
            popup.addstr(0, 0,
                         "Consensus Descriptor (%s):" % properties.fingerprint,
                         curses.A_STANDOUT)
        else:
            popup.addstr(0, 0, "Consensus Descriptor:", curses.A_STANDOUT)

        isEncryption = False  # true if line is part of an encryption block

        # checks if first line is in an encryption block
        for i in range(0, properties.scroll):
            lineText = properties.text[i].strip()
            if lineText in SIG_START_KEYS: isEncryption = True
            elif lineText in SIG_END_KEYS: isEncryption = False

        pageHeight = popup.maxY - 2
        numFieldWidth = int(math.log10(len(properties.text))) + 1
        lineNum = 1
        for i in range(
                properties.scroll,
                min(len(properties.text), properties.scroll + pageHeight)):
            lineText = properties.text[i].strip()

            numOffset = 0  # offset for line numbering
            if properties.showLineNum:
                popup.addstr(lineNum, xOffset,
                             ("%%%ii" % numFieldWidth) % (i + 1),
                             curses.A_BOLD | uiTools.getColor(LINE_NUM_COLOR))
                numOffset = numFieldWidth + 1

            if lineText:
                keyword = lineText.split()[0]  # first word of line
                remainder = lineText[len(keyword):]
                keywordFormat = curses.A_BOLD | uiTools.getColor(
                    properties.entryColor)
                remainderFormat = uiTools.getColor(properties.entryColor)

                if lineText.startswith(
                        HEADER_PREFIX[0]) or lineText.startswith(
                            HEADER_PREFIX[1]):
                    keyword, remainder = lineText, ""
                    keywordFormat = curses.A_BOLD | uiTools.getColor(
                        HEADER_COLOR)
                if lineText == UNRESOLVED_MSG or lineText == ERROR_MSG:
                    keyword, remainder = lineText, ""
                if lineText in SIG_START_KEYS:
                    keyword, remainder = lineText, ""
                    isEncryption = True
                    keywordFormat = curses.A_BOLD | uiTools.getColor(SIG_COLOR)
                elif lineText in SIG_END_KEYS:
                    keyword, remainder = lineText, ""
                    isEncryption = False
                    keywordFormat = curses.A_BOLD | uiTools.getColor(SIG_COLOR)
                elif isEncryption:
                    keyword, remainder = lineText, ""
                    keywordFormat = uiTools.getColor(SIG_COLOR)

                lineNum, xLoc = controller.addstr_wrap(popup, lineNum, 0,
                                                       keyword, keywordFormat,
                                                       xOffset + numOffset,
                                                       popup.maxX - 1,
                                                       popup.maxY - 1)
                lineNum, xLoc = controller.addstr_wrap(
                    popup, lineNum, xLoc, remainder, remainderFormat,
                    xOffset + numOffset, popup.maxX - 1, popup.maxY - 1)

            lineNum += 1
            if lineNum > pageHeight: break

    popup.refresh()
コード例 #37
0
ファイル: countPopup.py プロジェクト: gsathya/arm
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()
コード例 #38
0
ファイル: wizard.py プロジェクト: JustMe23/arm
 def getDisplayAttr(self):
   myColor = OPTION_COLOR if self.isEnabled() else DISABLED_COLOR
   return curses.A_BOLD | uiTools.getColor(myColor)
コード例 #39
0
ファイル: wizard.py プロジェクト: JustMe23/arm
def promptRelayType(initialSelection):
  """
  Provides a prompt for selecting the general role we'd like Tor to run with.
  This returns a RelayType enumeration for the selection, or CANCEL if the
  dialog was canceled.
  """
  
  options = [ConfigOption(opt, "role", opt) for opt in RelayType.values()]
  options.append(ConfigOption(CANCEL, "general", CANCEL))
  selection = RelayType.indexOf(initialSelection)
  height = 28
  
  # drops the resume option if it isn't applicable
  control = cli.controller.getController()
  if not control.getTorManager().isTorrcAvailable():
    options.pop(0)
    height -= 3
    selection -= 1
  
  popup, _, _ = cli.popups.init(height, 58)
  if not popup: return
  
  try:
    popup.win.box()
    curses.cbreak()
    
    # provides the welcoming message
    topContent = _splitStr(CONFIG["wizard.message.role"], 54)
    for i in range(len(topContent)):
      popup.addstr(i + 1, 2, topContent[i], curses.A_BOLD | uiTools.getColor(MSG_COLOR))
    
    while True:
      y, offset = len(topContent) + 1, 0
      
      for opt in options:
        optionFormat = uiTools.getColor(MSG_COLOR)
        if opt == options[selection]: optionFormat |= curses.A_STANDOUT
        
        # Curses has a weird bug where there's a one-pixel alignment
        # difference between bold and regular text, so it looks better
        # to render the whitespace here as not being bold.
        
        offset += 1
        label = opt.getLabel(" ")
        popup.addstr(y + offset, 2, label, optionFormat | curses.A_BOLD)
        popup.addstr(y + offset, 2 + len(label), " " * (54 - len(label)), optionFormat)
        offset += 1
        
        for line in opt.getDescription(52, " "):
          popup.addstr(y + offset, 2, uiTools.padStr(line, 54), optionFormat)
          offset += 1
      
      popup.win.refresh()
      key = control.getScreen().getch()
      
      if key == curses.KEY_UP: selection = (selection - 1) % len(options)
      elif key == curses.KEY_DOWN: selection = (selection + 1) % len(options)
      elif uiTools.isSelectionKey(key): return options[selection].getValue()
      elif key in (27, ord('q'), ord('Q')): return CANCEL # esc or q - cancel
  finally:
    cli.popups.finalize()
コード例 #40
0
ファイル: wizard.py プロジェクト: JustMe23/arm
def promptConfigOptions(relayType, config, disabledOpt):
  """
  Prompts the user for the configuration of an internal relay.
  """
  
  topContent = _splitStr(CONFIG.get("wizard.message.%s" % relayType.lower(), ""), 54)
  
  options = [config[opt] for opt in RelayOptions[relayType] if not opt in disabledOpt]
  options.append(Options.DIVIDER)
  options.append(ConfigOption(BACK, "general", "(to role selection)"))
  options.append(ConfigOption(NEXT, "general", "(to confirm options)"))
  
  popupHeight = len(topContent) + len(options) + DESC_SIZE + 5
  popup, _, _ = cli.popups.init(popupHeight, 58)
  if not popup: return
  control = cli.controller.getController()
  key, selection = 0, 0
  
  try:
    curses.cbreak()
    
    while True:
      popup.win.erase()
      popup.win.box()
      
      # provides the description for the relay type
      for i in range(len(topContent)):
        popup.addstr(i + 1, 2, topContent[i], curses.A_BOLD | uiTools.getColor(MSG_COLOR))
      
      y, offset = len(topContent) + 1, 0
      for opt in options:
        if opt == Options.DIVIDER:
          offset += 1
          continue
        
        optionFormat = opt.getDisplayAttr()
        if opt == options[selection]: optionFormat |= curses.A_STANDOUT
        
        offset, indent = offset + 1, 0
        if opt.getKey() in CONFIG["wizard.suboptions"]:
          # If the next entry is also a suboption then show a 'T', otherwise
          # end the bracketing.
          
          bracketChar, nextIndex = curses.ACS_LLCORNER, options.index(opt) + 1
          if nextIndex < len(options) and isinstance(options[nextIndex], ConfigOption):
            if options[nextIndex].getKey() in CONFIG["wizard.suboptions"]:
              bracketChar = curses.ACS_LTEE
          
          popup.addch(y + offset, 3, bracketChar, opt.getDisplayAttr())
          popup.addch(y + offset, 4, curses.ACS_HLINE, opt.getDisplayAttr())
          
          indent = 3
        
        labelFormat = " %%-%is%%s" % (30 - indent)
        label = labelFormat % (opt.getLabel(), opt.getDisplayValue())
        popup.addstr(y + offset, 2 + indent, uiTools.padStr(label, 54 - indent), optionFormat)
        
        # little hack to make "Block" policies red
        if opt != options[selection] and not opt.getValue() and opt.getKey() in CUSTOM_POLICIES:
          optionFormat = curses.A_BOLD | uiTools.getColor("red")
          popup.addstr(y + offset, 33, opt.getDisplayValue(), optionFormat)
      
      # divider between the options and description
      offset += 2
      popup.addch(y + offset, 0, curses.ACS_LTEE)
      popup.addch(y + offset, popup.getWidth() - 1, curses.ACS_RTEE)
      popup.hline(y + offset, 1, popup.getWidth() - 2)
      
      # description for the currently selected option
      for line in options[selection].getDescription(54, " "):
        offset += 1
        popup.addstr(y + offset, 1, line, uiTools.getColor(MSG_COLOR))
      
      popup.win.refresh()
      key = control.getScreen().getch()
      
      if key in (curses.KEY_UP, curses.KEY_DOWN):
        posOffset = -1 if key == curses.KEY_UP else 1
        selection = (selection + posOffset) % len(options)
        
        # skips disabled options and dividers
        while options[selection] == Options.DIVIDER or not options[selection].isEnabled():
          selection = (selection + posOffset) % len(options)
      elif uiTools.isSelectionKey(key):
        if selection == len(options) - 2: return BACK # selected back
        elif selection == len(options) - 1: return NEXT # selected next
        elif isinstance(options[selection], ToggleConfigOption):
          options[selection].toggle()
        else:
          newValue = popup.getstr(y + selection + 1, 33, options[selection].getValue(), curses.A_STANDOUT | uiTools.getColor(OPTION_COLOR), 23)
          if newValue:
            try: options[selection].setValue(newValue.strip())
            except ValueError, exc:
              cli.popups.showMsg(str(exc), 3)
              cli.controller.getController().redraw()
      elif key in (27, ord('q'), ord('Q')): return CANCEL
  finally:
    cli.popups.finalize()
コード例 #41
0
ファイル: circEntry.py プロジェクト: JustMe23/arm
 def getDetails(self, width):
   if not self.isBuilt:
     detailFormat = curses.A_BOLD | uiTools.getColor(connEntry.CATEGORY_COLOR[self.getType()])
     return [("Building Circuit...", detailFormat)]
   else: return connEntry.ConnectionLine.getDetails(self, width)
コード例 #42
0
ファイル: wizard.py プロジェクト: JustMe23/arm
def showConfirmationDialog(torrcContents, torrcLocation):
  """
  Shows a confirmation dialog with the given torrc contents, returning CANCEL,
  NEXT, or BACK based on the selection.
  
  Arguments:
    torrcContents - lines of torrc contents to be presented
    torrcLocation - path where the torrc will be placed
  """
  
  torrcLines = torrcContents.split("\n")
  options = ["Cancel", "Back to Setup", "Start Tor"]
  
  control = cli.controller.getController()
  screenHeight = control.getScreen().getmaxyx()[0]
  stickyHeight = sum([stickyPanel.getHeight() for stickyPanel in control.getStickyPanels()])
  isScrollbarVisible = len(torrcLines) + stickyHeight + 5 > screenHeight
  
  xOffset = 3 if isScrollbarVisible else 0
  popup, width, height = cli.popups.init(len(torrcLines) + 5, 84 + xOffset)
  if not popup: return False
  
  try:
    scroll, selection = 0, 2
    curses.cbreak()
    
    while True:
      popup.win.erase()
      popup.win.box()
      
      # renders the scrollbar
      if isScrollbarVisible:
        popup.addScrollBar(scroll, scroll + height - 5, len(torrcLines), 1, height - 4, 1)
      
      # shows the path where the torrc will be placed
      titleMsg = "The following will be placed at '%s':" % torrcLocation
      popup.addstr(0, 0, titleMsg, curses.A_STANDOUT)
      
      # renders the torrc contents
      for i in range(scroll, min(len(torrcLines), height - 5 + scroll)):
        # parses the argument and comment from options
        option, arg, comment = uiTools.cropStr(torrcLines[i], width - 4 - xOffset), "", ""
        
        div = option.find("#")
        if div != -1: option, comment = option[:div], option[div:]
        
        div = option.strip().find(" ")
        if div != -1: option, arg = option[:div], option[div:]
        
        drawX = 2 + xOffset
        popup.addstr(i + 1 - scroll, drawX, option, curses.A_BOLD | uiTools.getColor("green"))
        drawX += len(option)
        popup.addstr(i + 1 - scroll, drawX, arg, curses.A_BOLD | uiTools.getColor("cyan"))
        drawX += len(arg)
        popup.addstr(i + 1 - scroll, drawX, comment, uiTools.getColor("white"))
      
      # divider between the torrc and the options
      popup.addch(height - 4, 0, curses.ACS_LTEE)
      popup.addch(height - 4, width, curses.ACS_RTEE)
      popup.hline(height - 4, 1, width - 1)
      if isScrollbarVisible: popup.addch(height - 4, 2, curses.ACS_BTEE)
      
      # renders the selection options
      confirmationMsg = "Run tor with the above configuration?"
      popup.addstr(height - 3, width - len(confirmationMsg) - 1, confirmationMsg, uiTools.getColor("green") | curses.A_BOLD)
      
      drawX = width - 1
      for i in range(len(options) - 1, -1, -1):
        optionLabel = " %s " % options[i]
        drawX -= (len(optionLabel) + 4)
        
        selectionFormat = curses.A_STANDOUT if i == selection else curses.A_NORMAL
        popup.addstr(height - 2, drawX, "[", uiTools.getColor("green"))
        popup.addstr(height - 2, drawX + 1, optionLabel, uiTools.getColor("green") | selectionFormat | curses.A_BOLD)
        popup.addstr(height - 2, drawX + len(optionLabel) + 1, "]", uiTools.getColor("green"))
        
        drawX -= 1 # space gap between the options
      
      popup.win.refresh()
      key = cli.controller.getController().getScreen().getch()
      
      if key == curses.KEY_LEFT:
        selection = (selection - 1) % len(options)
      elif key == curses.KEY_RIGHT:
        selection = (selection + 1) % len(options)
      elif uiTools.isScrollKey(key):
        scroll = uiTools.getScrollPosition(key, scroll, height - 5, len(torrcLines))
      elif uiTools.isSelectionKey(key):
        if selection == 0: return CANCEL
        elif selection == 1: return BACK
        else: return NEXT
      elif key in (27, ord('q'), ord('Q')): return CANCEL
  finally:
    cli.popups.finalize()
コード例 #43
0
ファイル: wizard.py プロジェクト: fhawah12345/fhawah12345.mra
 def getDisplayAttr(self):
     myColor = OPTION_COLOR if self.isEnabled() else DISABLED_COLOR
     return curses.A_BOLD | uiTools.getColor(myColor)
コード例 #44
0
ファイル: logPanel.py プロジェクト: refnode/arm
 def draw(self, width, height):
   """
   Redraws message log. Entries stretch to use available space and may
   contain up to two lines. Starts with newest entries.
   """
   
   currentLog = self.getAttr("msgLog")
   
   self.valsLock.acquire()
   self._lastLoggedEvents, self._lastUpdate = list(currentLog), time.time()
   
   # draws the top label
   if self.isTitleVisible():
     self.addstr(0, 0, self._getTitle(width), curses.A_STANDOUT)
   
   # restricts scroll location to valid bounds
   self.scroll = max(0, min(self.scroll, self.lastContentHeight - height + 1))
   
   # draws left-hand scroll bar if content's longer than the height
   msgIndent, dividerIndent = 1, 0 # offsets for scroll bar
   isScrollBarVisible = self.lastContentHeight > height - 1
   if isScrollBarVisible:
     msgIndent, dividerIndent = 3, 2
     self.addScrollBar(self.scroll, self.scroll + height - 1, self.lastContentHeight, 1)
   
   # draws log entries
   lineCount = 1 - self.scroll
   seenFirstDateDivider = False
   dividerAttr, duplicateAttr = curses.A_BOLD | uiTools.getColor("yellow"), curses.A_BOLD | uiTools.getColor("green")
   
   isDatesShown = self.regexFilter == None and self._config["features.log.showDateDividers"]
   eventLog = getDaybreaks(currentLog, self.isPaused()) if isDatesShown else list(currentLog)
   if not self.showDuplicates:
     deduplicatedLog = getDuplicates(eventLog)
     
     if deduplicatedLog == None:
       msg = "Deduplication took too long. Its current implementation has difficulty handling large logs so disabling it to keep the interface responsive."
       log.log(log.WARN, msg)
       self.showDuplicates = True
       deduplicatedLog = [(entry, 0) for entry in eventLog]
   else: deduplicatedLog = [(entry, 0) for entry in eventLog]
   
   # determines if we have the minimum width to show date dividers
   showDaybreaks = width - dividerIndent >= 3
   
   while deduplicatedLog:
     entry, duplicateCount = deduplicatedLog.pop(0)
     
     if self.regexFilter and not self.regexFilter.search(entry.getDisplayMessage()):
       continue  # filter doesn't match log message - skip
     
     # checks if we should be showing a divider with the date
     if entry.type == DAYBREAK_EVENT:
       # bottom of the divider
       if seenFirstDateDivider:
         if lineCount >= 1 and lineCount < height and showDaybreaks:
           self.addch(lineCount, dividerIndent, curses.ACS_LLCORNER,  dividerAttr)
           self.hline(lineCount, dividerIndent + 1, width - dividerIndent - 2, dividerAttr)
           self.addch(lineCount, width - 1, curses.ACS_LRCORNER, dividerAttr)
         
         lineCount += 1
       
       # top of the divider
       if lineCount >= 1 and lineCount < height and showDaybreaks:
         timeLabel = time.strftime(" %B %d, %Y ", time.localtime(entry.timestamp))
         self.addch(lineCount, dividerIndent, curses.ACS_ULCORNER, dividerAttr)
         self.addch(lineCount, dividerIndent + 1, curses.ACS_HLINE, dividerAttr)
         self.addstr(lineCount, dividerIndent + 2, timeLabel, curses.A_BOLD | dividerAttr)
         
         lineLength = width - dividerIndent - len(timeLabel) - 3
         self.hline(lineCount, dividerIndent + len(timeLabel) + 2, lineLength, dividerAttr)
         self.addch(lineCount, dividerIndent + len(timeLabel) + 2 + lineLength, curses.ACS_URCORNER, dividerAttr)
       
       seenFirstDateDivider = True
       lineCount += 1
     else:
       # entry contents to be displayed, tuples of the form:
       # (msg, formatting, includeLinebreak)
       displayQueue = []
       
       msgComp = entry.getDisplayMessage().split("\n")
       for i in range(len(msgComp)):
         font = curses.A_BOLD if "ERR" in entry.type else curses.A_NORMAL # emphasizes ERR messages
         displayQueue.append((msgComp[i].strip(), font | uiTools.getColor(entry.color), i != len(msgComp) - 1))
       
       if duplicateCount:
         pluralLabel = "s" if duplicateCount > 1 else ""
         duplicateMsg = DUPLICATE_MSG % (duplicateCount, pluralLabel)
         displayQueue.append((duplicateMsg, duplicateAttr, False))
       
       cursorLoc, lineOffset = msgIndent, 0
       maxEntriesPerLine = self._config["features.log.maxLinesPerEntry"]
       while displayQueue:
         msg, format, includeBreak = displayQueue.pop(0)
         drawLine = lineCount + lineOffset
         if lineOffset == maxEntriesPerLine: break
         
         maxMsgSize = width - cursorLoc - 1
         if len(msg) > maxMsgSize:
           # message is too long - break it up
           if lineOffset == maxEntriesPerLine - 1:
             msg = uiTools.cropStr(msg, maxMsgSize)
           else:
             msg, remainder = uiTools.cropStr(msg, maxMsgSize, 4, 4, uiTools.Ending.HYPHEN, True)
             displayQueue.insert(0, (remainder.strip(), format, includeBreak))
           
           includeBreak = True
         
         if drawLine < height and drawLine >= 1:
           if seenFirstDateDivider and width - dividerIndent >= 3 and showDaybreaks:
             self.addch(drawLine, dividerIndent, curses.ACS_VLINE, dividerAttr)
             self.addch(drawLine, width - 1, curses.ACS_VLINE, dividerAttr)
           
           self.addstr(drawLine, cursorLoc, msg, format)
         
         cursorLoc += len(msg)
         
         if includeBreak or not displayQueue:
           lineOffset += 1
           cursorLoc = msgIndent + ENTRY_INDENT
       
       lineCount += lineOffset
     
     # if this is the last line and there's room, then draw the bottom of the divider
     if not deduplicatedLog and seenFirstDateDivider:
       if lineCount < height and showDaybreaks:
         self.addch(lineCount, dividerIndent, curses.ACS_LLCORNER, dividerAttr)
         self.hline(lineCount, dividerIndent + 1, width - dividerIndent - 2, dividerAttr)
         self.addch(lineCount, width - 1, curses.ACS_LRCORNER, dividerAttr)
       
       lineCount += 1
   
   # redraw the display if...
   # - lastContentHeight was off by too much
   # - we're off the bottom of the page
   newContentHeight = lineCount + self.scroll - 1
   contentHeightDelta = abs(self.lastContentHeight - newContentHeight)
   forceRedraw, forceRedrawReason = True, ""
   
   if contentHeightDelta >= CONTENT_HEIGHT_REDRAW_THRESHOLD:
     forceRedrawReason = "estimate was off by %i" % contentHeightDelta
   elif newContentHeight > height and self.scroll + height - 1 > newContentHeight:
     forceRedrawReason = "scrolled off the bottom of the page"
   elif not isScrollBarVisible and newContentHeight > height - 1:
     forceRedrawReason = "scroll bar wasn't previously visible"
   elif isScrollBarVisible and newContentHeight <= height - 1:
     forceRedrawReason = "scroll bar shouldn't be visible"
   else: forceRedraw = False
   
   self.lastContentHeight = newContentHeight
   if forceRedraw:
     forceRedrawReason = "redrawing the log panel with the corrected content height (%s)" % forceRedrawReason
     log.log(self._config["log.logPanel.forceDoubleRedraw"], forceRedrawReason)
     self.redraw(True)
   
   self.valsLock.release()
コード例 #45
0
ファイル: wizard.py プロジェクト: fhawah12345/fhawah12345.mra
def promptConfigOptions(relayType, config, disabledOpt):
    """
  Prompts the user for the configuration of an internal relay.
  """

    topContent = _splitStr(
        CONFIG.get("wizard.message.%s" % relayType.lower(), ""), 54)

    options = [
        config[opt] for opt in RelayOptions[relayType]
        if not opt in disabledOpt
    ]
    options.append(Options.DIVIDER)
    options.append(ConfigOption(BACK, "general", "(to role selection)"))
    options.append(ConfigOption(NEXT, "general", "(to confirm options)"))

    popupHeight = len(topContent) + len(options) + DESC_SIZE + 5
    popup, _, _ = cli.popups.init(popupHeight, 58)
    if not popup: return
    control = cli.controller.getController()
    key, selection = 0, 0

    try:
        curses.cbreak()

        while True:
            popup.win.erase()
            popup.win.box()

            # provides the description for the relay type
            for i in range(len(topContent)):
                popup.addstr(i + 1, 2, topContent[i],
                             curses.A_BOLD | uiTools.getColor(MSG_COLOR))

            y, offset = len(topContent) + 1, 0
            for opt in options:
                if opt == Options.DIVIDER:
                    offset += 1
                    continue

                optionFormat = opt.getDisplayAttr()
                if opt == options[selection]: optionFormat |= curses.A_STANDOUT

                offset, indent = offset + 1, 0
                if opt.getKey() in CONFIG["wizard.suboptions"]:
                    # If the next entry is also a suboption then show a 'T', otherwise
                    # end the bracketing.

                    bracketChar, nextIndex = curses.ACS_LLCORNER, options.index(
                        opt) + 1
                    if nextIndex < len(options) and isinstance(
                            options[nextIndex], ConfigOption):
                        if options[nextIndex].getKey(
                        ) in CONFIG["wizard.suboptions"]:
                            bracketChar = curses.ACS_LTEE

                    popup.addch(y + offset, 3, bracketChar,
                                opt.getDisplayAttr())
                    popup.addch(y + offset, 4, curses.ACS_HLINE,
                                opt.getDisplayAttr())

                    indent = 3

                labelFormat = " %%-%is%%s" % (30 - indent)
                label = labelFormat % (opt.getLabel(), opt.getDisplayValue())
                popup.addstr(y + offset, 2 + indent,
                             uiTools.padStr(label, 54 - indent), optionFormat)

                # little hack to make "Block" policies red
                if opt != options[selection] and not opt.getValue(
                ) and opt.getKey() in CUSTOM_POLICIES:
                    optionFormat = curses.A_BOLD | uiTools.getColor("red")
                    popup.addstr(y + offset, 33, opt.getDisplayValue(),
                                 optionFormat)

            # divider between the options and description
            offset += 2
            popup.addch(y + offset, 0, curses.ACS_LTEE)
            popup.addch(y + offset, popup.getWidth() - 1, curses.ACS_RTEE)
            popup.hline(y + offset, 1, popup.getWidth() - 2)

            # description for the currently selected option
            for line in options[selection].getDescription(54, " "):
                offset += 1
                popup.addstr(y + offset, 1, line, uiTools.getColor(MSG_COLOR))

            popup.win.refresh()
            key = control.getScreen().getch()

            if key in (curses.KEY_UP, curses.KEY_DOWN):
                posOffset = -1 if key == curses.KEY_UP else 1
                selection = (selection + posOffset) % len(options)

                # skips disabled options and dividers
                while options[selection] == Options.DIVIDER or not options[
                        selection].isEnabled():
                    selection = (selection + posOffset) % len(options)
            elif uiTools.isSelectionKey(key):
                if selection == len(options) - 2: return BACK  # selected back
                elif selection == len(options) - 1:
                    return NEXT  # selected next
                elif isinstance(options[selection], ToggleConfigOption):
                    options[selection].toggle()
                else:
                    newValue = popup.getstr(
                        y + selection + 1, 33, options[selection].getValue(),
                        curses.A_STANDOUT | uiTools.getColor(OPTION_COLOR), 23)
                    if newValue:
                        try:
                            options[selection].setValue(newValue.strip())
                        except ValueError, exc:
                            cli.popups.showMsg(str(exc), 3)
                            cli.controller.getController().redraw()
            elif key in (27, ord('q'), ord('Q')):
                return CANCEL
コード例 #46
0
ファイル: torrcPanel.py プロジェクト: katmagic/arm
 def draw(self, subwindow, width, height):
   self.valsLock.acquire()
   
   # If true, we assume that the cached value in self._lastContentHeight is
   # still accurate, and stop drawing when there's nothing more to display.
   # Otherwise the self._lastContentHeight is suspect, and we'll process all
   # the content to check if it's right (and redraw again with the corrected
   # height if not).
   trustLastContentHeight = self._lastContentHeightArgs == (width, height)
   
   # restricts scroll location to valid bounds
   self.scroll = max(0, min(self.scroll, self._lastContentHeight - height + 1))
   
   renderedContents, corrections, confLocation = None, {}, None
   if self.configType == TORRC:
     loadedTorrc = torConfig.getTorrc()
     loadedTorrc.getLock().acquire()
     confLocation = loadedTorrc.getConfigLocation()
     
     if not loadedTorrc.isLoaded():
       renderedContents = ["### Unable to load the torrc ###"]
     else:
       renderedContents = loadedTorrc.getDisplayContents(self.stripComments)
       
       # constructs a mapping of line numbers to the issue on it
       corrections = dict((lineNum, (issue, msg)) for lineNum, issue, msg in loadedTorrc.getCorrections())
     
     loadedTorrc.getLock().release()
   else:
     loadedArmrc = conf.getConfig("arm")
     confLocation = loadedArmrc.path
     renderedContents = list(loadedArmrc.rawContents)
   
   # offset to make room for the line numbers
   lineNumOffset = 0
   if self.showLineNum:
     if len(renderedContents) == 0: lineNumOffset = 2
     else: lineNumOffset = int(math.log10(len(renderedContents))) + 2
   
   # draws left-hand scroll bar if content's longer than the height
   scrollOffset = 0
   if self._config["features.config.file.showScrollbars"] and self._lastContentHeight > height - 1:
     scrollOffset = 3
     self.addScrollBar(self.scroll, self.scroll + height - 1, self._lastContentHeight, 1)
   
   displayLine = -self.scroll + 1 # line we're drawing on
   
   # draws the top label
   if self.showLabel:
     sourceLabel = "Tor" if self.configType == TORRC else "Arm"
     locationLabel = " (%s)" % confLocation if confLocation else ""
     self.addstr(0, 0, "%s Configuration File%s:" % (sourceLabel, locationLabel), curses.A_STANDOUT)
   
   isMultiline = False # true if we're in the middle of a multiline torrc entry
   for lineNumber in range(0, len(renderedContents)):
     lineText = renderedContents[lineNumber]
     lineText = lineText.rstrip() # remove ending whitespace
     
     # blank lines are hidden when stripping comments
     if self.stripComments and not lineText: continue
     
     # splits the line into its component (msg, format) tuples
     lineComp = {"option": ["", curses.A_BOLD | uiTools.getColor("green")],
                 "argument": ["", curses.A_BOLD | uiTools.getColor("cyan")],
                 "correction": ["", curses.A_BOLD | uiTools.getColor("cyan")],
                 "comment": ["", uiTools.getColor("white")]}
     
     # parses the comment
     commentIndex = lineText.find("#")
     if commentIndex != -1:
       lineComp["comment"][0] = lineText[commentIndex:]
       lineText = lineText[:commentIndex]
     
     # splits the option and argument, preserving any whitespace around them
     strippedLine = lineText.strip()
     optionIndex = strippedLine.find(" ")
     if isMultiline:
       # part of a multiline entry started on a previous line so everything
       # is part of the argument
       lineComp["argument"][0] = lineText
     elif optionIndex == -1:
       # no argument provided
       lineComp["option"][0] = lineText
     else:
       optionText = strippedLine[:optionIndex]
       optionEnd = lineText.find(optionText) + len(optionText)
       lineComp["option"][0] = lineText[:optionEnd]
       lineComp["argument"][0] = lineText[optionEnd:]
     
     # flags following lines as belonging to this multiline entry if it ends
     # with a slash
     if strippedLine: isMultiline = strippedLine.endswith("\\")
     
     # gets the correction
     if lineNumber in corrections:
       lineIssue, lineIssueMsg = corrections[lineNumber]
       
       if lineIssue in (torConfig.VAL_DUPLICATE, torConfig.VAL_IS_DEFAULT):
         lineComp["option"][1] = curses.A_BOLD | uiTools.getColor("blue")
         lineComp["argument"][1] = curses.A_BOLD | uiTools.getColor("blue")
       elif lineIssue == torConfig.VAL_MISMATCH:
         lineComp["argument"][1] = curses.A_BOLD | uiTools.getColor("red")
         lineComp["correction"][0] = " (%s)" % lineIssueMsg
       else:
         # For some types of configs the correction field is simply used to
         # provide extra data (for instance, the type for tor state fields).
         lineComp["correction"][0] = " (%s)" % lineIssueMsg
         lineComp["correction"][1] = curses.A_BOLD | uiTools.getColor("magenta")
     
     # draws the line number
     if self.showLineNum and displayLine < height and displayLine >= 1:
       lineNumStr = ("%%%ii" % (lineNumOffset - 1)) % (lineNumber + 1)
       self.addstr(displayLine, scrollOffset, lineNumStr, curses.A_BOLD | uiTools.getColor("yellow"))
     
     # draws the rest of the components with line wrap
     cursorLoc, lineOffset = lineNumOffset + scrollOffset, 0
     maxLinesPerEntry = self._config["features.config.file.maxLinesPerEntry"]
     displayQueue = [lineComp[entry] for entry in ("option", "argument", "correction", "comment")]
     
     while displayQueue:
       msg, format = displayQueue.pop(0)
       
       maxMsgSize, includeBreak = width - cursorLoc, False
       if len(msg) >= maxMsgSize:
         # message is too long - break it up
         if lineOffset == maxLinesPerEntry - 1:
           msg = uiTools.cropStr(msg, maxMsgSize)
         else:
           includeBreak = True
           msg, remainder = uiTools.cropStr(msg, maxMsgSize, 4, 4, uiTools.END_WITH_HYPHEN, True)
           displayQueue.insert(0, (remainder.strip(), format))
       
       drawLine = displayLine + lineOffset
       if msg and drawLine < height and drawLine >= 1:
         self.addstr(drawLine, cursorLoc, msg, format)
       
       # If we're done, and have added content to this line, then start
       # further content on the next line.
       cursorLoc += len(msg)
       includeBreak |= not displayQueue and cursorLoc != lineNumOffset + scrollOffset
       
       if includeBreak:
         lineOffset += 1
         cursorLoc = lineNumOffset + scrollOffset
     
     displayLine += max(lineOffset, 1)
     
     if trustLastContentHeight and displayLine >= height: break
   
   if not trustLastContentHeight:
     self._lastContentHeightArgs = (width, height)
     newContentHeight = displayLine + self.scroll - 1
     
     if self._lastContentHeight != newContentHeight:
       self._lastContentHeight = newContentHeight
       self.redraw(True)
   
   self.valsLock.release()
コード例 #47
0
ファイル: configPanel.py プロジェクト: JustMe23/arm
 def showWriteDialog(self):
   """
   Provies an interface to confirm if the configuration is saved and, if so,
   where.
   """
   
   # display a popup for saving the current configuration
   configLines = torConfig.getCustomOptions(True)
   popup, width, height = popups.init(len(configLines) + 2)
   if not popup: return
   
   try:
     # displayed options (truncating the labels if there's limited room)
     if width >= 30: selectionOptions = ("Save", "Save As...", "Cancel")
     else: selectionOptions = ("Save", "Save As", "X")
     
     # checks if we can show options beside the last line of visible content
     isOptionLineSeparate = False
     lastIndex = min(height - 2, len(configLines) - 1)
     
     # if we don't have room to display the selection options and room to
     # grow then display the selection options on its own line
     if width < (30 + len(configLines[lastIndex])):
       popup.setHeight(height + 1)
       popup.redraw(True) # recreates the window instance
       newHeight, _ = popup.getPreferredSize()
       
       if newHeight > height:
         height = newHeight
         isOptionLineSeparate = True
     
     key, selection = 0, 2
     while not uiTools.isSelectionKey(key):
       # if the popup has been resized then recreate it (needed for the
       # proper border height)
       newHeight, newWidth = popup.getPreferredSize()
       if (height, width) != (newHeight, newWidth):
         height, width = newHeight, newWidth
         popup.redraw(True)
       
       # if there isn't room to display the popup then cancel it
       if height <= 2:
         selection = 2
         break
       
       popup.win.erase()
       popup.win.box()
       popup.addstr(0, 0, "Configuration being saved:", curses.A_STANDOUT)
       
       visibleConfigLines = height - 3 if isOptionLineSeparate else height - 2
       for i in range(visibleConfigLines):
         line = uiTools.cropStr(configLines[i], width - 2)
         
         if " " in line:
           option, arg = line.split(" ", 1)
           popup.addstr(i + 1, 1, option, curses.A_BOLD | uiTools.getColor("green"))
           popup.addstr(i + 1, len(option) + 2, arg, curses.A_BOLD | uiTools.getColor("cyan"))
         else:
           popup.addstr(i + 1, 1, line, curses.A_BOLD | uiTools.getColor("green"))
       
       # draws selection options (drawn right to left)
       drawX = width - 1
       for i in range(len(selectionOptions) - 1, -1, -1):
         optionLabel = selectionOptions[i]
         drawX -= (len(optionLabel) + 2)
         
         # if we've run out of room then drop the option (this will only
         # occure on tiny displays)
         if drawX < 1: break
         
         selectionFormat = curses.A_STANDOUT if i == selection else curses.A_NORMAL
         popup.addstr(height - 2, drawX, "[")
         popup.addstr(height - 2, drawX + 1, optionLabel, selectionFormat | curses.A_BOLD)
         popup.addstr(height - 2, drawX + len(optionLabel) + 1, "]")
         
         drawX -= 1 # space gap between the options
       
       popup.win.refresh()
       
       key = cli.controller.getController().getScreen().getch()
       if key == curses.KEY_LEFT: selection = max(0, selection - 1)
       elif key == curses.KEY_RIGHT: selection = min(len(selectionOptions) - 1, selection + 1)
     
     if selection in (0, 1):
       loadedTorrc, promptCanceled = torConfig.getTorrc(), False
       try: configLocation = loadedTorrc.getConfigLocation()
       except IOError: configLocation = ""
       
       if selection == 1:
         # prompts user for a configuration location
         configLocation = popups.inputPrompt("Save to (esc to cancel): ", configLocation)
         if not configLocation: promptCanceled = True
       
       if not promptCanceled:
         try:
           torConfig.saveConf(configLocation, configLines)
           msg = "Saved configuration to %s" % configLocation
         except IOError, exc:
           msg = "Unable to save configuration (%s)" % sysTools.getFileErrorMsg(exc)
         
         popups.showMsg(msg, 2)
   finally: popups.finalize()
コード例 #48
0
ファイル: headerPanel.py プロジェクト: twilde/arm
 def draw(self, width, height):
   self.valsLock.acquire()
   isWide = width + 1 >= MIN_DUAL_COL_WIDTH
   
   # space available for content
   if isWide:
     leftWidth = max(width / 2, 77)
     rightWidth = width - leftWidth
   else: leftWidth = rightWidth = width
   
   # Line 1 / Line 1 Left (system and tor version information)
   sysNameLabel = "arm - %s" % self.vals["sys/hostname"]
   contentSpace = min(leftWidth, 40)
   
   if len(sysNameLabel) + 10 <= contentSpace:
     sysTypeLabel = "%s %s" % (self.vals["sys/os"], self.vals["sys/version"])
     sysTypeLabel = uiTools.cropStr(sysTypeLabel, contentSpace - len(sysNameLabel) - 3, 4)
     self.addstr(0, 0, "%s (%s)" % (sysNameLabel, sysTypeLabel))
   else:
     self.addstr(0, 0, uiTools.cropStr(sysNameLabel, contentSpace))
   
   contentSpace = leftWidth - 43
   if 7 + len(self.vals["tor/version"]) + len(self.vals["tor/versionStatus"]) <= contentSpace:
     if self.vals["tor/version"] != "Unknown":
       versionColor = VERSION_STATUS_COLORS[self.vals["tor/versionStatus"]] if \
           self.vals["tor/versionStatus"] in VERSION_STATUS_COLORS else "white"
       labelPrefix = "Tor %s (" % self.vals["tor/version"]
       self.addstr(0, 43, labelPrefix)
       self.addstr(0, 43 + len(labelPrefix), self.vals["tor/versionStatus"], uiTools.getColor(versionColor))
       self.addstr(0, 43 + len(labelPrefix) + len(self.vals["tor/versionStatus"]), ")")
   elif 11 <= contentSpace:
     self.addstr(0, 43, uiTools.cropStr("Tor %s" % self.vals["tor/version"], contentSpace, 4))
   
   # Line 2 / Line 2 Left (tor ip/port information)
   x, includeControlPort = 0, True
   if self.vals["tor/orPort"]:
     myAddress = "Unknown"
     if self.vals["tor/orListenAddr"]: myAddress = self.vals["tor/orListenAddr"]
     elif self.vals["tor/address"]: myAddress = self.vals["tor/address"]
     
     # acting as a relay (we can assume certain parameters are set
     dirPortLabel = ", Dir Port: %s" % self.vals["tor/dirPort"] if self.vals["tor/dirPort"] != "0" else ""
     for label in (self.vals["tor/nickname"], " - " + myAddress, ":" + self.vals["tor/orPort"], dirPortLabel):
       if x + len(label) <= leftWidth:
         self.addstr(1, x, label)
         x += len(label)
       else: break
   else:
     # non-relay (client only)
     if self._isTorConnected:
       self.addstr(1, x, "Relaying Disabled", uiTools.getColor("cyan"))
       x += 17
     else:
       statusTime = torTools.getConn().getStatus()[1]
       
       if statusTime:
         statusTimeLabel = time.strftime("%H:%M %m/%d/%Y, ", time.localtime(statusTime))
       else: statusTimeLabel = "" # never connected to tor
       
       self.addstr(1, x, "Tor Disconnected", curses.A_BOLD | uiTools.getColor("red"))
       self.addstr(1, x + 16, " (%spress r to reconnect)" % statusTimeLabel)
       x += 39 + len(statusTimeLabel)
       includeControlPort = False
   
   if includeControlPort:
     if self.vals["tor/controlPort"] == "0":
       # connected via a control socket
       self.addstr(1, x, ", Control Socket: %s" % self.vals["tor/socketPath"])
     else:
       if self.vals["tor/isAuthPassword"]: authType = "password"
       elif self.vals["tor/isAuthCookie"]: authType = "cookie"
       else: authType = "open"
       
       if x + 19 + len(self.vals["tor/controlPort"]) + len(authType) <= leftWidth:
         authColor = "red" if authType == "open" else "green"
         self.addstr(1, x, ", Control Port (")
         self.addstr(1, x + 16, authType, uiTools.getColor(authColor))
         self.addstr(1, x + 16 + len(authType), "): %s" % self.vals["tor/controlPort"])
       elif x + 16 + len(self.vals["tor/controlPort"]) <= leftWidth:
         self.addstr(1, 0, ", Control Port: %s" % self.vals["tor/controlPort"])
   
   # Line 3 / Line 1 Right (system usage info)
   y, x = (0, leftWidth) if isWide else (2, 0)
   if self.vals["stat/rss"] != "0": memoryLabel = uiTools.getSizeLabel(int(self.vals["stat/rss"]))
   else: memoryLabel = "0"
   
   uptimeLabel = ""
   if self.vals["tor/startTime"]:
     if self.isPaused() or not self._isTorConnected:
       # freeze the uptime when paused or the tor process is stopped
       uptimeLabel = uiTools.getShortTimeLabel(self.getPauseTime() - self.vals["tor/startTime"])
     else:
       uptimeLabel = uiTools.getShortTimeLabel(time.time() - self.vals["tor/startTime"])
   
   sysFields = ((0, "cpu: %s%% tor, %s%% arm" % (self.vals["stat/%torCpu"], self.vals["stat/%armCpu"])),
                (27, "mem: %s (%s%%)" % (memoryLabel, self.vals["stat/%mem"])),
                (47, "pid: %s" % (self.vals["tor/pid"] if self._isTorConnected else "")),
                (59, "uptime: %s" % uptimeLabel))
   
   for (start, label) in sysFields:
     if start + len(label) <= rightWidth: self.addstr(y, x + start, label)
     else: break
   
   if self.vals["tor/orPort"]:
     # Line 4 / Line 2 Right (fingerprint, and possibly file descriptor usage)
     y, x = (1, leftWidth) if isWide else (3, 0)
     
     fingerprintLabel = uiTools.cropStr("fingerprint: %s" % self.vals["tor/fingerprint"], width)
     self.addstr(y, x, fingerprintLabel)
     
     # if there's room and we're able to retrieve both the file descriptor
     # usage and limit then it might be presented
     if width - x - 59 >= 20 and self.vals["tor/fdUsed"] and self.vals["tor/fdLimit"]:
       # display file descriptor usage if we're either configured to do so or
       # running out
       
       fdPercent = 100 * self.vals["tor/fdUsed"] / self.vals["tor/fdLimit"]
       
       if fdPercent >= 60 or self._config["features.showFdUsage"]:
         fdPercentLabel, fdPercentFormat = "%i%%" % fdPercent, curses.A_NORMAL
         if fdPercent >= 95:
           fdPercentFormat = curses.A_BOLD | uiTools.getColor("red")
         elif fdPercent >= 90:
           fdPercentFormat = uiTools.getColor("red")
         elif fdPercent >= 60:
           fdPercentFormat = uiTools.getColor("yellow")
         
         estimateChar = "?" if self.vals["tor/isFdLimitEstimate"] else ""
         baseLabel = "file desc: %i / %i%s (" % (self.vals["tor/fdUsed"], self.vals["tor/fdLimit"], estimateChar)
         
         self.addstr(y, x + 59, baseLabel)
         self.addstr(y, x + 59 + len(baseLabel), fdPercentLabel, fdPercentFormat)
         self.addstr(y, x + 59 + len(baseLabel) + len(fdPercentLabel), ")")
     
     # Line 5 / Line 3 Left (flags)
     if self._isTorConnected:
       y, x = (2 if isWide else 4, 0)
       self.addstr(y, x, "flags: ")
       x += 7
       
       if len(self.vals["tor/flags"]) > 0:
         for i in range(len(self.vals["tor/flags"])):
           flag = self.vals["tor/flags"][i]
           flagColor = FLAG_COLORS[flag] if flag in FLAG_COLORS.keys() else "white"
           
           self.addstr(y, x, flag, curses.A_BOLD | uiTools.getColor(flagColor))
           x += len(flag)
           
           if i < len(self.vals["tor/flags"]) - 1:
             self.addstr(y, x, ", ")
             x += 2
       else:
         self.addstr(y, x, "none", curses.A_BOLD | uiTools.getColor("cyan"))
     else:
       y = 2 if isWide else 4
       statusTime = torTools.getConn().getStatus()[1]
       statusTimeLabel = time.strftime("%H:%M %m/%d/%Y", time.localtime(statusTime))
       self.addstr(y, 0, "Tor Disconnected", curses.A_BOLD | uiTools.getColor("red"))
       self.addstr(y, 16, " (%s) - press r to reconnect" % statusTimeLabel)
     
     # Undisplayed / Line 3 Right (exit policy)
     if isWide:
       exitPolicy = self.vals["tor/exitPolicy"]
       
       # adds note when default exit policy is appended
       if exitPolicy == "": exitPolicy = "<default>"
       elif not exitPolicy.endswith((" *:*", " *")): exitPolicy += ", <default>"
       
       self.addstr(2, leftWidth, "exit policy: ")
       x = leftWidth + 13
       
       # color codes accepts to be green, rejects to be red, and default marker to be cyan
       isSimple = len(exitPolicy) > rightWidth - 13
       policies = exitPolicy.split(", ")
       for i in range(len(policies)):
         policy = policies[i].strip()
         policyLabel = policy.replace("accept", "").replace("reject", "").strip() if isSimple else policy
         
         policyColor = "white"
         if policy.startswith("accept"): policyColor = "green"
         elif policy.startswith("reject"): policyColor = "red"
         elif policy.startswith("<default>"): policyColor = "cyan"
         
         self.addstr(2, x, policyLabel, curses.A_BOLD | uiTools.getColor(policyColor))
         x += len(policyLabel)
         
         if i < len(policies) - 1:
           self.addstr(2, x, ", ")
           x += 2
   else:
     # (Client only) Undisplayed / Line 2 Right (new identity option)
     if isWide:
       conn = torTools.getConn()
       newnymWait = conn.getNewnymWait()
       
       msg = "press 'n' for a new identity"
       if newnymWait > 0:
         pluralLabel = "s" if newnymWait > 1 else ""
         msg = "building circuits, available again in %i second%s" % (newnymWait, pluralLabel)
       
       self.addstr(1, leftWidth, msg)
   
   self.valsLock.release()
コード例 #49
0
    def draw(self, width, height):
        self.valsLock.acquire()
        isWide = width + 1 >= MIN_DUAL_COL_WIDTH

        # space available for content
        if isWide:
            leftWidth = max(width / 2, 77)
            rightWidth = width - leftWidth
        else:
            leftWidth = rightWidth = width

        # Line 1 / Line 1 Left (system and tor version information)
        sysNameLabel = "arm - %s" % self.vals["sys/hostname"]
        contentSpace = min(leftWidth, 40)

        if len(sysNameLabel) + 10 <= contentSpace:
            sysTypeLabel = "%s %s" % (self.vals["sys/os"],
                                      self.vals["sys/version"])
            sysTypeLabel = uiTools.cropStr(
                sysTypeLabel, contentSpace - len(sysNameLabel) - 3, 4)
            self.addstr(0, 0, "%s (%s)" % (sysNameLabel, sysTypeLabel))
        else:
            self.addstr(0, 0, uiTools.cropStr(sysNameLabel, contentSpace))

        contentSpace = leftWidth - 43
        if 7 + len(self.vals["tor/version"]) + len(
                self.vals["tor/versionStatus"]) <= contentSpace:
            if self.vals["tor/version"] != "Unknown":
                versionColor = VERSION_STATUS_COLORS[self.vals["tor/versionStatus"]] if \
                    self.vals["tor/versionStatus"] in VERSION_STATUS_COLORS else "white"
                labelPrefix = "Tor %s (" % self.vals["tor/version"]
                self.addstr(0, 43, labelPrefix)
                self.addstr(0, 43 + len(labelPrefix),
                            self.vals["tor/versionStatus"],
                            uiTools.getColor(versionColor))
                self.addstr(
                    0, 43 + len(labelPrefix) +
                    len(self.vals["tor/versionStatus"]), ")")
        elif 11 <= contentSpace:
            self.addstr(
                0, 43,
                uiTools.cropStr("Tor %s" % self.vals["tor/version"],
                                contentSpace, 4))

        # Line 2 / Line 2 Left (tor ip/port information)
        x, includeControlPort = 0, True
        if self.vals["tor/orPort"]:
            myAddress = "Unknown"
            if self.vals["tor/orListenAddr"]:
                myAddress = self.vals["tor/orListenAddr"]
            elif self.vals["tor/address"]:
                myAddress = self.vals["tor/address"]

            # acting as a relay (we can assume certain parameters are set
            dirPortLabel = ", Dir Port: %s" % self.vals[
                "tor/dirPort"] if self.vals["tor/dirPort"] != "0" else ""
            for label in (self.vals["tor/nickname"], " - " + myAddress,
                          ":" + self.vals["tor/orPort"], dirPortLabel):
                if x + len(label) <= leftWidth:
                    self.addstr(1, x, label)
                    x += len(label)
                else:
                    break
        else:
            # non-relay (client only)
            if self._isTorConnected:
                self.addstr(1, x, "Relaying Disabled",
                            uiTools.getColor("cyan"))
                x += 17
            else:
                statusTime = torTools.getConn().getHeartbeat()

                if statusTime:
                    statusTimeLabel = time.strftime("%H:%M %m/%d/%Y, ",
                                                    time.localtime(statusTime))
                else:
                    statusTimeLabel = ""  # never connected to tor

                self.addstr(1, x, "Tor Disconnected",
                            curses.A_BOLD | uiTools.getColor("red"))
                self.addstr(1, x + 16,
                            " (%spress r to reconnect)" % statusTimeLabel)
                x += 39 + len(statusTimeLabel)
                includeControlPort = False

        if includeControlPort:
            if self.vals["tor/controlPort"] == "0":
                # connected via a control socket
                self.addstr(
                    1, x, ", Control Socket: %s" % self.vals["tor/socketPath"])
            else:
                if self.vals["tor/isAuthPassword"]: authType = "password"
                elif self.vals["tor/isAuthCookie"]: authType = "cookie"
                else: authType = "open"

                if x + 19 + len(self.vals["tor/controlPort"]) + len(
                        authType) <= leftWidth:
                    authColor = "red" if authType == "open" else "green"
                    self.addstr(1, x, ", Control Port (")
                    self.addstr(1, x + 16, authType,
                                uiTools.getColor(authColor))
                    self.addstr(1, x + 16 + len(authType),
                                "): %s" % self.vals["tor/controlPort"])
                elif x + 16 + len(self.vals["tor/controlPort"]) <= leftWidth:
                    self.addstr(
                        1, 0,
                        ", Control Port: %s" % self.vals["tor/controlPort"])

        # Line 3 / Line 1 Right (system usage info)
        y, x = (0, leftWidth) if isWide else (2, 0)
        if self.vals["stat/rss"] != "0":
            memoryLabel = str_tools.get_size_label(int(self.vals["stat/rss"]))
        else:
            memoryLabel = "0"

        uptimeLabel = ""
        if self.vals["tor/startTime"]:
            if self.isPaused() or not self._isTorConnected:
                # freeze the uptime when paused or the tor process is stopped
                uptimeLabel = str_tools.get_short_time_label(
                    self.getPauseTime() - self.vals["tor/startTime"])
            else:
                uptimeLabel = str_tools.get_short_time_label(
                    time.time() - self.vals["tor/startTime"])

        sysFields = ((0, "cpu: %s%% tor, %s%% arm" %
                      (self.vals["stat/%torCpu"], self.vals["stat/%armCpu"])),
                     (27, "mem: %s (%s%%)" %
                      (memoryLabel, self.vals["stat/%mem"])),
                     (47, "pid: %s" %
                      (self.vals["tor/pid"] if self._isTorConnected else "")),
                     (59, "uptime: %s" % uptimeLabel))

        for (start, label) in sysFields:
            if start + len(label) <= rightWidth:
                self.addstr(y, x + start, label)
            else:
                break

        if self.vals["tor/orPort"]:
            # Line 4 / Line 2 Right (fingerprint, and possibly file descriptor usage)
            y, x = (1, leftWidth) if isWide else (3, 0)

            fingerprintLabel = uiTools.cropStr(
                "fingerprint: %s" % self.vals["tor/fingerprint"], width)
            self.addstr(y, x, fingerprintLabel)

            # if there's room and we're able to retrieve both the file descriptor
            # usage and limit then it might be presented
            if width - x - 59 >= 20 and self.vals["tor/fdUsed"] and self.vals[
                    "tor/fdLimit"]:
                # display file descriptor usage if we're either configured to do so or
                # running out

                fdPercent = 100 * self.vals["tor/fdUsed"] / self.vals[
                    "tor/fdLimit"]

                if fdPercent >= 60 or CONFIG["features.showFdUsage"]:
                    fdPercentLabel, fdPercentFormat = "%i%%" % fdPercent, curses.A_NORMAL
                    if fdPercent >= 95:
                        fdPercentFormat = curses.A_BOLD | uiTools.getColor(
                            "red")
                    elif fdPercent >= 90:
                        fdPercentFormat = uiTools.getColor("red")
                    elif fdPercent >= 60:
                        fdPercentFormat = uiTools.getColor("yellow")

                    estimateChar = "?" if self.vals[
                        "tor/isFdLimitEstimate"] else ""
                    baseLabel = "file desc: %i / %i%s (" % (
                        self.vals["tor/fdUsed"], self.vals["tor/fdLimit"],
                        estimateChar)

                    self.addstr(y, x + 59, baseLabel)
                    self.addstr(y, x + 59 + len(baseLabel), fdPercentLabel,
                                fdPercentFormat)
                    self.addstr(y,
                                x + 59 + len(baseLabel) + len(fdPercentLabel),
                                ")")

            # Line 5 / Line 3 Left (flags)
            if self._isTorConnected:
                y, x = (2 if isWide else 4, 0)
                self.addstr(y, x, "flags: ")
                x += 7

                if len(self.vals["tor/flags"]) > 0:
                    for i in range(len(self.vals["tor/flags"])):
                        flag = self.vals["tor/flags"][i]
                        flagColor = FLAG_COLORS[
                            flag] if flag in FLAG_COLORS.keys() else "white"

                        self.addstr(
                            y, x, flag,
                            curses.A_BOLD | uiTools.getColor(flagColor))
                        x += len(flag)

                        if i < len(self.vals["tor/flags"]) - 1:
                            self.addstr(y, x, ", ")
                            x += 2
                else:
                    self.addstr(y, x, "none",
                                curses.A_BOLD | uiTools.getColor("cyan"))
            else:
                y = 2 if isWide else 4
                statusTime = torTools.getConn().getHeartbeat()
                statusTimeLabel = time.strftime("%H:%M %m/%d/%Y",
                                                time.localtime(statusTime))
                self.addstr(y, 0, "Tor Disconnected",
                            curses.A_BOLD | uiTools.getColor("red"))
                self.addstr(y, 16,
                            " (%s) - press r to reconnect" % statusTimeLabel)

            # Undisplayed / Line 3 Right (exit policy)
            if isWide:
                exitPolicy = self.vals["tor/exitPolicy"]

                # adds note when default exit policy is appended
                if exitPolicy == "": exitPolicy = "<default>"
                elif not exitPolicy.endswith((" *:*", " *")):
                    exitPolicy += ", <default>"

                self.addstr(2, leftWidth, "exit policy: ")
                x = leftWidth + 13

                # color codes accepts to be green, rejects to be red, and default marker to be cyan
                isSimple = len(exitPolicy) > rightWidth - 13
                policies = exitPolicy.split(", ")
                for i in range(len(policies)):
                    policy = policies[i].strip()
                    policyLabel = policy.replace("accept", "").replace(
                        "reject", "").strip() if isSimple else policy

                    policyColor = "white"
                    if policy.startswith("accept"): policyColor = "green"
                    elif policy.startswith("reject"): policyColor = "red"
                    elif policy.startswith("<default>"): policyColor = "cyan"

                    self.addstr(2, x, policyLabel,
                                curses.A_BOLD | uiTools.getColor(policyColor))
                    x += len(policyLabel)

                    if i < len(policies) - 1:
                        self.addstr(2, x, ", ")
                        x += 2
        else:
            # (Client only) Undisplayed / Line 2 Right (new identity option)
            if isWide:
                conn = torTools.getConn()
                newnymWait = conn.getNewnymWait()

                msg = "press 'n' for a new identity"
                if newnymWait > 0:
                    pluralLabel = "s" if newnymWait > 1 else ""
                    msg = "building circuits, available again in %i second%s" % (
                        newnymWait, pluralLabel)

                self.addstr(1, leftWidth, msg)

        self.valsLock.release()
コード例 #50
0
ファイル: graphPanel.py プロジェクト: refnode/arm
 def draw(self, width, height):
   """ Redraws graph panel """
   
   if self.currentDisplay:
     param = self.getAttr("stats")[self.currentDisplay]
     graphCol = min((width - 10) / 2, param.maxCol)
     
     primaryColor = uiTools.getColor(param.getColor(True))
     secondaryColor = uiTools.getColor(param.getColor(False))
     
     if self.isTitleVisible(): self.addstr(0, 0, param.getTitle(width), curses.A_STANDOUT)
     
     # top labels
     left, right = param.getHeaderLabel(width / 2, True), param.getHeaderLabel(width / 2, False)
     if left: self.addstr(1, 0, left, curses.A_BOLD | primaryColor)
     if right: self.addstr(1, graphCol + 5, right, curses.A_BOLD | secondaryColor)
     
     # determines max/min value on the graph
     if self.bounds == Bounds.GLOBAL_MAX:
       primaryMaxBound = int(param.maxPrimary[self.updateInterval])
       secondaryMaxBound = int(param.maxSecondary[self.updateInterval])
     else:
       # both Bounds.LOCAL_MAX and Bounds.TIGHT use local maxima
       if graphCol < 2:
         # nothing being displayed
         primaryMaxBound, secondaryMaxBound = 0, 0
       else:
         primaryMaxBound = int(max(param.primaryCounts[self.updateInterval][1:graphCol + 1]))
         secondaryMaxBound = int(max(param.secondaryCounts[self.updateInterval][1:graphCol + 1]))
     
     primaryMinBound = secondaryMinBound = 0
     if self.bounds == Bounds.TIGHT:
       primaryMinBound = int(min(param.primaryCounts[self.updateInterval][1:graphCol + 1]))
       secondaryMinBound = int(min(param.secondaryCounts[self.updateInterval][1:graphCol + 1]))
       
       # if the max = min (ie, all values are the same) then use zero lower
       # bound so a graph is still displayed
       if primaryMinBound == primaryMaxBound: primaryMinBound = 0
       if secondaryMinBound == secondaryMaxBound: secondaryMinBound = 0
     
     # displays upper and lower bounds
     self.addstr(2, 0, "%4i" % primaryMaxBound, primaryColor)
     self.addstr(self.graphHeight + 1, 0, "%4i" % primaryMinBound, primaryColor)
     
     self.addstr(2, graphCol + 5, "%4i" % secondaryMaxBound, secondaryColor)
     self.addstr(self.graphHeight + 1, graphCol + 5, "%4i" % secondaryMinBound, secondaryColor)
     
     # displays intermediate bounds on every other row
     if CONFIG["features.graph.showIntermediateBounds"]:
       ticks = (self.graphHeight - 3) / 2
       for i in range(ticks):
         row = self.graphHeight - (2 * i) - 3
         if self.graphHeight % 2 == 0 and i >= (ticks / 2): row -= 1
         
         if primaryMinBound != primaryMaxBound:
           primaryVal = (primaryMaxBound - primaryMinBound) * (self.graphHeight - row - 1) / (self.graphHeight - 1)
           if not primaryVal in (primaryMinBound, primaryMaxBound): self.addstr(row + 2, 0, "%4i" % primaryVal, primaryColor)
         
         if secondaryMinBound != secondaryMaxBound:
           secondaryVal = (secondaryMaxBound - secondaryMinBound) * (self.graphHeight - row - 1) / (self.graphHeight - 1)
           if not secondaryVal in (secondaryMinBound, secondaryMaxBound): self.addstr(row + 2, graphCol + 5, "%4i" % secondaryVal, secondaryColor)
     
     # creates bar graph (both primary and secondary)
     for col in range(graphCol):
       colCount = int(param.primaryCounts[self.updateInterval][col + 1]) - primaryMinBound
       colHeight = min(self.graphHeight, self.graphHeight * colCount / (max(1, primaryMaxBound) - primaryMinBound))
       for row in range(colHeight): self.addstr(self.graphHeight + 1 - row, col + 5, " ", curses.A_STANDOUT | primaryColor)
       
       colCount = int(param.secondaryCounts[self.updateInterval][col + 1]) - secondaryMinBound
       colHeight = min(self.graphHeight, self.graphHeight * colCount / (max(1, secondaryMaxBound) - secondaryMinBound))
       for row in range(colHeight): self.addstr(self.graphHeight + 1 - row, col + graphCol + 10, " ", curses.A_STANDOUT | secondaryColor)
     
     # bottom labeling of x-axis
     intervalSec = 1 # seconds per labeling
     for i in range(len(UPDATE_INTERVALS)):
       if i == self.updateInterval: intervalSec = UPDATE_INTERVALS[i][1]
     
     intervalSpacing = 10 if graphCol >= WIDE_LABELING_GRAPH_COL else 5
     unitsLabel, decimalPrecision = None, 0
     for i in range((graphCol - 4) / intervalSpacing):
       loc = (i + 1) * intervalSpacing
       timeLabel = uiTools.getTimeLabel(loc * intervalSec, decimalPrecision)
       
       if not unitsLabel: unitsLabel = timeLabel[-1]
       elif unitsLabel != timeLabel[-1]:
         # upped scale so also up precision of future measurements
         unitsLabel = timeLabel[-1]
         decimalPrecision += 1
       else:
         # if constrained on space then strips labeling since already provided
         timeLabel = timeLabel[:-1]
       
       self.addstr(self.graphHeight + 2, 4 + loc, timeLabel, primaryColor)
       self.addstr(self.graphHeight + 2, graphCol + 10 + loc, timeLabel, secondaryColor)
       
     param.draw(self, width, height) # allows current stats to modify the display