From ef0faaa2f430ba6d72c8173806bc9a3edc405c6b Mon Sep 17 00:00:00 2001
From: Michael Zeltner <m@niij.org>
Date: Sat, 28 Jul 2012 21:19:02 +0200
Subject: [PATCH] #6329 Select family by fingerprint or nickname (for named
 relays)

---
 task-6329/tor-relays-stats.py |   45 +++++++++++++++++++++++++++++++++++++----
 1 file changed, 41 insertions(+), 4 deletions(-)

diff --git a/task-6329/tor-relays-stats.py b/task-6329/tor-relays-stats.py
index 245a241..da30436 100755
--- a/task-6329/tor-relays-stats.py
+++ b/task-6329/tor-relays-stats.py
@@ -23,13 +23,43 @@ class RelayStats(object):
             self._data = json.load(file('details.json'))
         return self._data
 
-    def get_relays(self, countries=[], as_sets=[], exits_only=False, guards_only=False, inactive=False):
-        relays = []
+    def get_relays(self, countries=[], as_sets=[], exits_only=False, guards_only=False, inactive=False,
+                   family=None):
+        relays, all_r, mentions, fprint = [], self.data['relays'], False, None
         if countries:
             countries = [x.lower() for x in countries]
         if as_sets:
             as_sets = [x if not x.isdigit() else "AS" + x for x in as_sets]
-        for relay in self.data['relays']:
+        if family:
+            import re
+            if re.match(r'^[A-F0-9]{40}$', family):
+                try:
+                    relays.append(all_r[[relay['fingerprint'] for relay in all_r].index(family)])
+                except:
+                    return relays
+                fprint = '$%s' % family
+                if relays:
+                    family = relays[0].get('family', [])
+                    name = relays[0]['nickname'] if 'Named' in relays[0]['flags'] else False
+            else:
+                try:
+                    relays.append(all_r[[relay['nickname'] if 'Named' in relay['flags'] else None for relay in all_r].index(family)])
+                except:
+                    return relays
+                fprint = "$%s" % relays[0]['fingerprint']
+                family = relays[0].get('family', [])
+                name = relays[0]['nickname']
+            if relays and (countries and not relays[0].get('country', ' ') in countries) or \
+               (as_sets and not relays[0].get('as_number', ' ') in as_sets) or \
+               (inactive and not inactive == relays[0]['running']) or \
+               (exits_only and not relays[0].get('exit_probability', -1) > 0.0) or \
+               (guards_only and not relays[0].get('guard_probability', -1) > 0.0):
+                relays.pop()
+        for relay in all_r:
+            if fprint:
+                mentions = relay.get('family', [])
+            if fprint and (not family or not mentions):
+                continue
             if not inactive and inactive == relay['running']:
                 continue
             if countries and not relay.get('country', ' ') in countries:
@@ -40,6 +70,10 @@ class RelayStats(object):
                 continue
             if guards_only and not relay.get('guard_probability', -1) > 0.0:
                 continue
+            if fprint and family and mentions and not ('$%s' % relay['fingerprint'] in family or \
+               relay['nickname'] in family if 'Named' in relay['flags'] else '' and \
+               fprint in mentions or name in mentions if name else ''):
+                continue
             relays.append(relay)
         return relays
 
@@ -155,6 +189,8 @@ if '__main__' == __name__:
                      help="select only relays suitable for exit position")
     group.add_option("-g", "--guards-only", action="store_true",
                      help="select only relays suitable for guard position")
+    group.add_option("-f", "--family", action="store", type="string", metavar="RELAY",
+                     help="select family by fingerprint or nickname (for named relays)")
     parser.add_option_group(group)
     group = OptionGroup(parser, "Grouping options")
     group.add_option("-A", "--by-as", action="store_true", default=False,
@@ -183,7 +219,8 @@ if '__main__' == __name__:
                               as_sets=options.ases,
                               exits_only=options.exits_only,
                               guards_only=options.guards_only,
-                              inactive=options.inactive)
+                              inactive=options.inactive,
+                              family=options.family)
     grouped_relays = stats.group_relays(relays,
                      by_country=options.by_country,
                      by_as_number=options.by_as)
-- 
1.7.9.5

