11#! /usr/bin/env python
22
3- """Print the long name of an Internet domain .
3+ """Print mappings between country names and DNS country codes .
44
55This script will take an Internet address and print out where in the
66world that message originated from, based on the top-level domain code
@@ -10,8 +10,22 @@ found in the address. Addresses can be in any of the following forms:
1010 host.domain.xx -- any Internet host or network name
1111 [email protected] -- an Internet email address 1212
13+ If the country code is not recognizable, it will attempt a reverse lookup,
14+ searching for the country name and printing a list of matching country codes.
15+ You can force reverse mappings with the `-r' flag (see below).
16+
17+ For example:
18+
19+ % world tz us
20+ tz originated from Tanzania, United Republic of
21+ us originated from United States
22+
23+ % world united
24+
25+
1326Country codes are maintained by the RIPE Network Coordination Centre,
14- in coordination with the ISO 3166 Maintenance Agency at DIN Berlin.
27+ in coordination with the ISO 3166 Maintenance Agency at DIN Berlin. The
28+ authoritative source of counry code mappings is:
1529
1630 <url:ftp://info.ripe.net/iso3166-countrycodes>
1731
@@ -28,29 +42,46 @@ Usage: %s [-d] [-p|-P file] [-h] addr [addr ...]
2842 Print mapping of all top-level domains.
2943
3044 --parse file
31- --p file
32- --P file
33- --Parse file
34- Parse an iso3166-countrycodes file (given as the argument).
35- This first the two letter country code (it ignores the three
36- letter code), followed by the country name. With -P option,
37- output is in the form of a Python dictionary, and country
38- names are normalized w.r.t. capitalization. This makes it
39- appropriate for cutting and pasting back into this file.
45+ -p file
46+ Parse an iso3166-countrycodes file extracting the two letter country
47+ code followed by the country name. Note that the three leter country
48+ code and number, which are also provided in the standard format file,
49+ are ignored.
50+
51+ --outputdict
52+ -o
53+ With used in conjunction with the `-p' option, output is in the form
54+ of a Python dictionary, and country names are normalized
55+ w.r.t. capitalization. This makes it appropriate for cutting and
56+ pasting back into this file.
57+
58+ --reverse
59+ -r
60+ Force reverse lookup. In this mode the address can be any Python
61+ regular expression; this is matched against all country names and a
62+ list of matching mappings is printed. In normal mode (e.g. without
63+ this flag), reverse lookup is performed on addresses if no matching
64+ country code is found.
4065
4166 -h
4267 --help
4368 Print this message.
4469
4570"""
46- __version__ = '2 .0'
71+ __version__ = '3 .0'
4772__author__ = 'Barry Warsaw <[email protected] >' 4873__source__ = '<url:http://www.python.org/~bwarsaw/pyware/>'
4974
5075
5176import sys
5277import string
5378import getopt
79+ try :
80+ import re
81+ except ImportError :
82+ print sys .argv [0 ], 'requires Python 1.5'
83+ sys .exit (1 )
84+
5485
5586
5687
@@ -59,28 +90,48 @@ def usage(status=0):
5990 sys .exit (status )
6091
6192
93+
6294def resolve (rawaddr ):
6395 parts = string .splitfields (rawaddr , '.' )
6496 if not len (parts ):
65- print 'No top- level domain in:' , rawaddr
66- return
97+ # no top level domain found, bounce it to the next step
98+ return rawaddr
6799 addr = parts [- 1 ]
68- if nameorg .has_key (addr ):
69- print rawaddr , 'is from a' , nameorg [addr ], 'organization'
70- elif country .has_key (addr ):
71- print rawaddr , 'originated from' , country [addr ]
100+ if nameorgs .has_key (addr ):
101+ print rawaddr , 'is from a' , nameorgs [addr ], 'organization'
102+ return None
103+ elif countries .has_key (addr ):
104+ print rawaddr , 'originated from' , countries [addr ]
105+ return None
72106 else :
73- print 'Where in the world is %s?' % rawaddr
107+ # Not resolved, bounce it to the next step
108+ return rawaddr
74109
75110
76111
77- def parse (file , normalize ):
78- try :
79- import re
80- except ImportError :
81- print 'Parsing requires Python 1.5'
82- sys .exit (1 )
112+ def reverse (regexp ):
113+ matches = []
114+ cre = re .compile (regexp , re .IGNORECASE )
115+ for code , country in all .items ():
116+ mo = cre .search (country )
117+ if mo :
118+ matches .append (code )
119+ # print results
120+ if not matches :
121+ # not resolved, bounce it to the next step
122+ return regexp
123+ if len (matches ) == 1 :
124+ code = matches [0 ]
125+ print regexp , "matches code `%s', %s" % (code , all [code ])
126+ else :
127+ print regexp , 'matches %d countries:' % len (matches )
128+ for code in matches :
129+ print " %s: %s" % (code , all [code ])
130+ return None
83131
132+
133+
134+ def parse (file , normalize ):
84135 try :
85136 fp = open (file )
86137 except IOError , (err , msg ):
@@ -149,20 +200,23 @@ def main():
149200 dump = 0
150201 parsefile = None
151202 normalize = 0
203+ forcerev = 0
152204
153- opts , args = getopt .getopt (sys .argv [1 :],
154- 'p:P:hd' ,
155- ['parse' , 'Parse' , 'PARSE' , 'help' , 'dump' ])
205+ opts , args = getopt .getopt (
206+ sys .argv [1 :],
207+ 'p:rohd' ,
208+ ['parse' , 'reverse' , 'outputdict' , 'help' , 'dump' ])
156209 for arg , val in opts :
157210 if arg in ('-h' , '--help' ):
158211 help = 1
159212 elif arg in ('-d' , '--dump' ):
160213 dump = 1
161214 elif arg in ('-p' , '--parse' ):
162215 parsefile = val
163- elif arg in ('-P' , '--Parse' , '--PARSE' ):
164- parsefile = val
216+ elif arg in ('-o' , '--output' ):
165217 normalize = 1
218+ elif arg in ('-r' , '--reverse' ):
219+ forcerev = 1
166220
167221 if help :
168222 usage (status )
@@ -182,12 +236,16 @@ def main():
182236 elif parsefile :
183237 parse (parsefile , normalize )
184238 else :
185- map (resolve , args )
239+ if not forcerev :
240+ args = filter (None , map (resolve , args ))
241+ args = filter (None , map (reverse , args ))
242+ for arg in args :
243+ print 'Where in the world is %s?' % arg
186244
187245
188246
189247# The mappings
190- nameorg = {
248+ nameorgs = {
191249 "arpa" : "Arpanet" ,
192250 "com" : "commercial" ,
193251 "edu" : "educational" ,
@@ -200,7 +258,7 @@ nameorg = {
200258
201259
202260
203- country = {
261+ countries = {
204262 "af" : "Afghanistan" ,
205263 "al" : "Albania" ,
206264 "dz" : "Algeria" ,
@@ -442,6 +500,9 @@ country = {
442500 "zw" : "Zimbabwe" ,
443501 }
444502
503+ all = nameorgs .copy ()
504+ all .update (countries )
505+
445506
446507if __name__ == '__main__' :
447508 main ()
0 commit comments