~ubuntu-branches/ubuntu/maverick/python3.1/maverick

« back to all changes in this revision

Viewing changes to Tools/world/world

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2009-03-23 00:01:27 UTC
  • Revision ID: james.westby@ubuntu.com-20090323000127-5fstfxju4ufrhthq
Tags: upstream-3.1~a1+20090322
ImportĀ upstreamĀ versionĀ 3.1~a1+20090322

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#! /usr/bin/env python
 
2
 
 
3
"""world -- Print mappings between country names and DNS country codes.
 
4
 
 
5
Contact: Barry Warsaw
 
6
Email:   barry@python.org
 
7
Version: %(__version__)s
 
8
 
 
9
This script will take a list of Internet addresses and print out where in the
 
10
world those addresses originate from, based on the top-level domain country
 
11
code found in the address.  Addresses can be in any of the following forms:
 
12
 
 
13
    xx                -- just the country code or top-level domain identifier
 
14
    host.domain.xx    -- any Internet host or network name
 
15
    somebody@where.xx -- an Internet email address
 
16
 
 
17
If no match is found, the address is interpreted as a regular expression and a
 
18
reverse lookup is attempted.  This script will search the country names and
 
19
print a list of matching entries.  You can force reverse mappings with the
 
20
`-r' flag (see below).
 
21
 
 
22
For example:
 
23
 
 
24
    %% world tz us
 
25
    tz originated from Tanzania, United Republic of
 
26
    us originated from United States
 
27
 
 
28
    %% world united
 
29
    united matches 6 countries:
 
30
        ae: United Arab Emirates
 
31
        uk: United Kingdom (common practice)
 
32
        um: United States Minor Outlying Islands
 
33
        us: United States
 
34
        tz: Tanzania, United Republic of
 
35
        gb: United Kingdom
 
36
 
 
37
Country codes are maintained by the RIPE Network Coordination Centre,
 
38
in coordination with the ISO 3166 Maintenance Agency at DIN Berlin.  The
 
39
authoritative source of country code mappings is:
 
40
 
 
41
    <url:ftp://ftp.ripe.net/iso3166-countrycodes.txt>
 
42
 
 
43
The latest known change to this information was:
 
44
 
 
45
    Monday, 10 October 2006, 17:59:51 UTC 2006
 
46
 
 
47
This script also knows about non-geographic top-level domains, and the
 
48
additional ccTLDs reserved by IANA.
 
49
 
 
50
Usage: %(PROGRAM)s [-d] [-p file] [-o] [-h] addr [addr ...]
 
51
 
 
52
    --dump
 
53
    -d
 
54
        Print mapping of all top-level domains.
 
55
 
 
56
    --parse file
 
57
    -p file
 
58
        Parse an iso3166-countrycodes file extracting the two letter country
 
59
        code followed by the country name.  Note that the three letter country
 
60
        codes and numbers, which are also provided in the standard format
 
61
        file, are ignored.
 
62
 
 
63
    --outputdict
 
64
    -o
 
65
        When used in conjunction with the `-p' option, output is in the form
 
66
        of a Python dictionary, and country names are normalized
 
67
        w.r.t. capitalization.  This makes it appropriate for cutting and
 
68
        pasting back into this file.  Output is always to standard out.
 
69
 
 
70
    --reverse
 
71
    -r
 
72
        Force reverse lookup.  In this mode the address can be any Python
 
73
        regular expression; this is matched against all country names and a
 
74
        list of matching mappings is printed.  In normal mode (e.g. without
 
75
        this flag), reverse lookup is performed on addresses if no matching
 
76
        country code is found.
 
77
 
 
78
    -h
 
79
    --help
 
80
        Print this message.
 
81
"""
 
82
__version__ = '$Revision: 59581 $'
 
83
 
 
84
 
 
85
import sys
 
86
import getopt
 
87
import re
 
88
 
 
89
PROGRAM = sys.argv[0]
 
90
 
 
91
 
 
92
 
 
93
def usage(code, msg=''):
 
94
    print(__doc__ % globals())
 
95
    if msg:
 
96
        print(msg)
 
97
    sys.exit(code)
 
98
 
 
99
 
 
100
 
 
101
def resolve(rawaddr):
 
102
    parts = rawaddr.split('.')
 
103
    if not len(parts):
 
104
        # no top level domain found, bounce it to the next step
 
105
        return rawaddr
 
106
    addr = parts[-1]
 
107
    if addr in nameorgs:
 
108
        print(rawaddr, 'is in the', nameorgs[addr], 'top level domain')
 
109
        return None
 
110
    elif addr in countries:
 
111
        print(rawaddr, 'originated from', countries[addr])
 
112
        return None
 
113
    else:
 
114
        # Not resolved, bounce it to the next step
 
115
        return rawaddr
 
116
 
 
117
 
 
118
 
 
119
def reverse(regexp):
 
120
    matches = []
 
121
    cre = re.compile(regexp, re.IGNORECASE)
 
122
    for code, country in all.items():
 
123
        mo = cre.search(country)
 
124
        if mo:
 
125
            matches.append(code)
 
126
    # print results
 
127
    if not matches:
 
128
        # not resolved, bounce it to the next step
 
129
        return regexp
 
130
    if len(matches) == 1:
 
131
        code = matches[0]
 
132
        print(regexp, "matches code `%s', %s" % (code, all[code]))
 
133
    else:
 
134
        print(regexp, 'matches %d countries:' % len(matches))
 
135
        for code in matches:
 
136
            print("    %s: %s" % (code, all[code]))
 
137
    return None
 
138
 
 
139
 
 
140
 
 
141
def parse(file, normalize):
 
142
    try:
 
143
        fp = open(file)
 
144
    except IOError as err:
 
145
        errno, msg = err.args
 
146
        print(msg, ':', file)
 
147
        return
 
148
 
 
149
    cre = re.compile('(.*?)[ \t]+([A-Z]{2})[ \t]+[A-Z]{3}[ \t]+[0-9]{3}')
 
150
    scanning = 0
 
151
 
 
152
    if normalize:
 
153
        print('countries = {')
 
154
 
 
155
    while 1:
 
156
        line = fp.readline()
 
157
        if line == '':
 
158
            break                       # EOF
 
159
        if scanning:
 
160
            mo = cre.match(line)
 
161
            if not mo:
 
162
                line = line.strip()
 
163
                if not line:
 
164
                    continue
 
165
                elif line[0] == '-':
 
166
                    break
 
167
                else:
 
168
                    print('Could not parse line:', line)
 
169
                    continue
 
170
            country, code = mo.group(1, 2)
 
171
            if normalize:
 
172
                words = country.split()
 
173
                for i in range(len(words)):
 
174
                    w = words[i]
 
175
                    # XXX special cases
 
176
                    if w in ('AND', 'OF', 'OF)', 'name:', 'METROPOLITAN'):
 
177
                        words[i] = w.lower()
 
178
                    elif w == 'THE' and i != 1:
 
179
                        words[i] = w.lower()
 
180
                    elif len(w) > 3 and w[1] == "'":
 
181
                        words[i] = w[0:3].upper() + w[3:].lower()
 
182
                    elif w in ('(U.S.)', 'U.S.'):
 
183
                        pass
 
184
                    elif w[0] == '(' and w != '(local':
 
185
                        words[i] = '(' + w[1:].capitalize()
 
186
                    elif w.find('-') != -1:
 
187
                        words[i] = '-'.join(
 
188
                            [s.capitalize() for s in w.split('-')])
 
189
                    else:
 
190
                        words[i] = w.capitalize()
 
191
                code = code.lower()
 
192
                country = ' '.join(words)
 
193
                print('    "%s": "%s",' % (code, country))
 
194
            else:
 
195
                print(code, country)
 
196
 
 
197
        elif line[0] == '-':
 
198
            scanning = 1
 
199
 
 
200
    if normalize:
 
201
        print('    }')
 
202
 
 
203
 
 
204
def main():
 
205
    help = 0
 
206
    status = 0
 
207
    dump = 0
 
208
    parsefile = None
 
209
    normalize = 0
 
210
    forcerev = 0
 
211
 
 
212
    try:
 
213
        opts, args = getopt.getopt(
 
214
            sys.argv[1:],
 
215
            'p:rohd',
 
216
            ['parse=', 'reverse', 'outputdict', 'help', 'dump'])
 
217
    except getopt.error as msg:
 
218
        usage(1, msg)
 
219
 
 
220
    for opt, arg in opts:
 
221
        if opt in ('-h', '--help'):
 
222
            help = 1
 
223
        elif opt in ('-d', '--dump'):
 
224
            dump = 1
 
225
        elif opt in ('-p', '--parse'):
 
226
            parsefile = arg
 
227
        elif opt in ('-o', '--outputdict'):
 
228
            normalize = 1
 
229
        elif opt in ('-r', '--reverse'):
 
230
            forcerev = 1
 
231
 
 
232
    if help:
 
233
        usage(status)
 
234
 
 
235
    if dump:
 
236
        print('Official country coded domains:')
 
237
        codes = sorted(countries)
 
238
        for code in codes:
 
239
            print('      %2s:' % code, countries[code])
 
240
 
 
241
        print('\nOther top-level domains:')
 
242
        codes = sorted(nameorgs)
 
243
        for code in codes:
 
244
            print('  %6s:' % code, nameorgs[code])
 
245
    elif parsefile:
 
246
        parse(parsefile, normalize)
 
247
    else:
 
248
        if not forcerev:
 
249
            args = filter(None, map(resolve, args))
 
250
        args = filter(None, map(reverse, args))
 
251
        for arg in args:
 
252
            print('Where in the world is %s?' % arg)
 
253
 
 
254
 
 
255
 
 
256
# The mappings
 
257
nameorgs = {
 
258
    # New top level domains as described by ICANN
 
259
    # http://www.icann.org/tlds/
 
260
    "aero": "air-transport industry",
 
261
    "asia": "from Asia/for Asia",
 
262
    "arpa": "Arpanet",
 
263
    "biz": "business",
 
264
    "cat": "Catalan community",
 
265
    "com": "commercial",
 
266
    "coop": "cooperatives",
 
267
    "edu": "educational",
 
268
    "gov": "government",
 
269
    "info": "unrestricted `info'",
 
270
    "int": "international",
 
271
    "jobs": "employment-related",
 
272
    "mil": "military",
 
273
    "mobi": "mobile specific",
 
274
    "museum": "museums",
 
275
    "name": "`name' (for registration by individuals)",
 
276
    "net": "networking",
 
277
    "org": "non-commercial",
 
278
    "pro": "professionals",
 
279
    "tel": "business telecommunications",
 
280
    "travel": "travel and tourism",
 
281
    # These additional ccTLDs are included here even though they are not part
 
282
    # of ISO 3166.  IANA has a decoding table listing all reserved ccTLDs:
 
283
    #
 
284
    # http://www.iso.org/iso/iso-3166-1_decoding_table
 
285
    #
 
286
    # Note that `uk' is the common practice country code for the United
 
287
    # Kingdom.  AFAICT, the official `gb' code is routinely ignored!
 
288
    #
 
289
    # <D.M.Pick@qmw.ac.uk> tells me that `uk' was long in use before ISO3166
 
290
    # was adopted for top-level DNS zone names (although in the reverse order
 
291
    # like uk.ac.qmw) and was carried forward (with the reversal) to avoid a
 
292
    # large-scale renaming process as the UK switched from their old `Coloured
 
293
    # Book' protocols over X.25 to Internet protocols over IP.
 
294
    #
 
295
    # See <url:ftp://ftp.ripe.net/ripe/docs/ripe-159.txt>
 
296
    #
 
297
    # Also, `su', while obsolete is still in limited use.
 
298
    "ac": "Ascension Island",
 
299
    "cp": "Clipperton Island",
 
300
    "dg": "Diego Garcia",
 
301
    "ea": "Ceuta, Melilla",
 
302
    "eu": "European Union",
 
303
    "fx": "Metropolitan France",
 
304
    "ic": "Canary Islands",
 
305
    "ta": "Tristan da Cunha",
 
306
    "uk": "United Kingdom (common practice)",
 
307
    "su": "Soviet Union (still in limited use)",
 
308
    }
 
309
 
 
310
 
 
311
 
 
312
countries = {
 
313
    "af": "Afghanistan",
 
314
    "ax": "Aland Islands",
 
315
    "al": "Albania",
 
316
    "dz": "Algeria",
 
317
    "as": "American Samoa",
 
318
    "ad": "Andorra",
 
319
    "ao": "Angola",
 
320
    "ai": "Anguilla",
 
321
    "aq": "Antarctica",
 
322
    "ag": "Antigua and Barbuda",
 
323
    "ar": "Argentina",
 
324
    "am": "Armenia",
 
325
    "aw": "Aruba",
 
326
    "au": "Australia",
 
327
    "at": "Austria",
 
328
    "az": "Azerbaijan",
 
329
    "bs": "Bahamas",
 
330
    "bh": "Bahrain",
 
331
    "bd": "Bangladesh",
 
332
    "bb": "Barbados",
 
333
    "by": "Belarus",
 
334
    "be": "Belgium",
 
335
    "bz": "Belize",
 
336
    "bj": "Benin",
 
337
    "bm": "Bermuda",
 
338
    "bt": "Bhutan",
 
339
    "bo": "Bolivia",
 
340
    "ba": "Bosnia and Herzegovina",
 
341
    "bw": "Botswana",
 
342
    "bv": "Bouvet Island",
 
343
    "br": "Brazil",
 
344
    "io": "British Indian Ocean Territory",
 
345
    "bn": "Brunei Darussalam",
 
346
    "bg": "Bulgaria",
 
347
    "bf": "Burkina Faso",
 
348
    "bi": "Burundi",
 
349
    "kh": "Cambodia",
 
350
    "cm": "Cameroon",
 
351
    "ca": "Canada",
 
352
    "cv": "Cape Verde",
 
353
    "ky": "Cayman Islands",
 
354
    "cf": "Central African Republic",
 
355
    "td": "Chad",
 
356
    "cl": "Chile",
 
357
    "cn": "China",
 
358
    "cx": "Christmas Island",
 
359
    "cc": "Cocos (Keeling) Islands",
 
360
    "co": "Colombia",
 
361
    "km": "Comoros",
 
362
    "cg": "Congo",
 
363
    "cd": "Congo, The Democratic Republic of the",
 
364
    "ck": "Cook Islands",
 
365
    "cr": "Costa Rica",
 
366
    "ci": "Cote D'Ivoire",
 
367
    "hr": "Croatia",
 
368
    "cu": "Cuba",
 
369
    "cy": "Cyprus",
 
370
    "cz": "Czech Republic",
 
371
    "dk": "Denmark",
 
372
    "dj": "Djibouti",
 
373
    "dm": "Dominica",
 
374
    "do": "Dominican Republic",
 
375
    "ec": "Ecuador",
 
376
    "eg": "Egypt",
 
377
    "sv": "El Salvador",
 
378
    "gq": "Equatorial Guinea",
 
379
    "er": "Eritrea",
 
380
    "ee": "Estonia",
 
381
    "et": "Ethiopia",
 
382
    "fk": "Falkland Islands (Malvinas)",
 
383
    "fo": "Faroe Islands",
 
384
    "fj": "Fiji",
 
385
    "fi": "Finland",
 
386
    "fr": "France",
 
387
    "gf": "French Guiana",
 
388
    "pf": "French Polynesia",
 
389
    "tf": "French Southern Territories",
 
390
    "ga": "Gabon",
 
391
    "gm": "Gambia",
 
392
    "ge": "Georgia",
 
393
    "de": "Germany",
 
394
    "gh": "Ghana",
 
395
    "gi": "Gibraltar",
 
396
    "gr": "Greece",
 
397
    "gl": "Greenland",
 
398
    "gd": "Grenada",
 
399
    "gp": "Guadeloupe",
 
400
    "gu": "Guam",
 
401
    "gt": "Guatemala",
 
402
    "gg": "Guernsey",
 
403
    "gn": "Guinea",
 
404
    "gw": "Guinea-Bissau",
 
405
    "gy": "Guyana",
 
406
    "ht": "Haiti",
 
407
    "hm": "Heard Island and Mcdonald Islands",
 
408
    "va": "Holy See (Vatican City State)",
 
409
    "hn": "Honduras",
 
410
    "hk": "Hong Kong",
 
411
    "hu": "Hungary",
 
412
    "is": "Iceland",
 
413
    "in": "India",
 
414
    "id": "Indonesia",
 
415
    "ir": "Iran (Islamic Republic of)",
 
416
    "iq": "Iraq",
 
417
    "ie": "Ireland",
 
418
    "im": "Isle of Man",
 
419
    "il": "Israel",
 
420
    "it": "Italy",
 
421
    "jm": "Jamaica",
 
422
    "jp": "Japan",
 
423
    "je": "Jersey",
 
424
    "jo": "Jordan",
 
425
    "kz": "Kazakhstan",
 
426
    "ke": "Kenya",
 
427
    "ki": "Kiribati",
 
428
    "kp": "Korea, Democratic People's Republic of",
 
429
    "kr": "Korea, Republic of",
 
430
    "kw": "Kuwait",
 
431
    "kg": "Kyrgyzstan",
 
432
    "la": "Lao People's Democratic Republic",
 
433
    "lv": "Latvia",
 
434
    "lb": "Lebanon",
 
435
    "ls": "Lesotho",
 
436
    "lr": "Liberia",
 
437
    "ly": "Libyan Arab Jamahiriya",
 
438
    "li": "Liechtenstein",
 
439
    "lt": "Lithuania",
 
440
    "lu": "Luxembourg",
 
441
    "mo": "Macao",
 
442
    "mk": "Macedonia, The Former Yugoslav Republic of",
 
443
    "mg": "Madagascar",
 
444
    "mw": "Malawi",
 
445
    "my": "Malaysia",
 
446
    "mv": "Maldives",
 
447
    "ml": "Mali",
 
448
    "mt": "Malta",
 
449
    "mh": "Marshall Islands",
 
450
    "mq": "Martinique",
 
451
    "mr": "Mauritania",
 
452
    "mu": "Mauritius",
 
453
    "yt": "Mayotte",
 
454
    "mx": "Mexico",
 
455
    "fm": "Micronesia, Federated States of",
 
456
    "md": "Moldova, Republic of",
 
457
    "mc": "Monaco",
 
458
    "mn": "Mongolia",
 
459
    "me": "Montenegro",
 
460
    "ms": "Montserrat",
 
461
    "ma": "Morocco",
 
462
    "mz": "Mozambique",
 
463
    "mm": "Myanmar",
 
464
    "na": "Namibia",
 
465
    "nr": "Nauru",
 
466
    "np": "Nepal",
 
467
    "nl": "Netherlands",
 
468
    "an": "Netherlands Antilles",
 
469
    "nc": "New Caledonia",
 
470
    "nz": "New Zealand",
 
471
    "ni": "Nicaragua",
 
472
    "ne": "Niger",
 
473
    "ng": "Nigeria",
 
474
    "nu": "Niue",
 
475
    "nf": "Norfolk Island",
 
476
    "mp": "Northern Mariana Islands",
 
477
    "no": "Norway",
 
478
    "om": "Oman",
 
479
    "pk": "Pakistan",
 
480
    "pw": "Palau",
 
481
    "ps": "Palestinian Territory, Occupied",
 
482
    "pa": "Panama",
 
483
    "pg": "Papua New Guinea",
 
484
    "py": "Paraguay",
 
485
    "pe": "Peru",
 
486
    "ph": "Philippines",
 
487
    "pn": "Pitcairn",
 
488
    "pl": "Poland",
 
489
    "pt": "Portugal",
 
490
    "pr": "Puerto Rico",
 
491
    "qa": "Qatar",
 
492
    "re": "Reunion",
 
493
    "ro": "Romania",
 
494
    "ru": "Russian Federation",
 
495
    "rw": "Rwanda",
 
496
    "sh": "Saint Helena",
 
497
    "kn": "Saint Kitts and Nevis",
 
498
    "lc": "Saint Lucia",
 
499
    "pm": "Saint Pierre and Miquelon",
 
500
    "vc": "Saint Vincent and the Grenadines",
 
501
    "ws": "Samoa",
 
502
    "sm": "San Marino",
 
503
    "st": "Sao Tome and Principe",
 
504
    "sa": "Saudi Arabia",
 
505
    "sn": "Senegal",
 
506
    "rs": "Serbia",
 
507
    "sc": "Seychelles",
 
508
    "sl": "Sierra Leone",
 
509
    "sg": "Singapore",
 
510
    "sk": "Slovakia",
 
511
    "si": "Slovenia",
 
512
    "sb": "Solomon Islands",
 
513
    "so": "Somalia",
 
514
    "za": "South Africa",
 
515
    "gs": "South Georgia and the South Sandwich Islands",
 
516
    "es": "Spain",
 
517
    "lk": "Sri Lanka",
 
518
    "sd": "Sudan",
 
519
    "sr": "Suriname",
 
520
    "sj": "Svalbard and Jan Mayen",
 
521
    "sh": "St. Helena",
 
522
    "pm": "St. Pierre and Miquelon",
 
523
    "sz": "Swaziland",
 
524
    "se": "Sweden",
 
525
    "ch": "Switzerland",
 
526
    "sy": "Syrian Arab Republic",
 
527
    "tw": "Taiwan, Province of China",
 
528
    "tj": "Tajikistan",
 
529
    "tz": "Tanzania, United Republic of",
 
530
    "th": "Thailand",
 
531
    "tl": "Timor-Leste",
 
532
    "tg": "Togo",
 
533
    "tk": "Tokelau",
 
534
    "to": "Tonga",
 
535
    "tt": "Trinidad and Tobago",
 
536
    "tn": "Tunisia",
 
537
    "tr": "Turkey",
 
538
    "tm": "Turkmenistan",
 
539
    "tc": "Turks and Caicos Islands",
 
540
    "tv": "Tuvalu",
 
541
    "ug": "Uganda",
 
542
    "ua": "Ukraine",
 
543
    "ae": "United Arab Emirates",
 
544
    "gb": "United Kingdom",
 
545
    "us": "United States",
 
546
    "um": "United States Minor Outlying Islands",
 
547
    "uy": "Uruguay",
 
548
    "uz": "Uzbekistan",
 
549
    "vu": "Vanuatu",
 
550
    "va": "Vatican City State (Holy See)",
 
551
    "ve": "Venezuela",
 
552
    "vn": "Viet Nam",
 
553
    "vg": "Virgin Islands (British)",
 
554
    "vi": "Virgin Islands (U.S.)",
 
555
    "wf": "Wallis and Futuna",
 
556
    "eh": "Western Sahara",
 
557
    "ye": "Yemen",
 
558
    "yu": "Yugoslavia",
 
559
    "zm": "Zambia",
 
560
    "zw": "Zimbabwe",
 
561
    }
 
562
 
 
563
all = nameorgs.copy()
 
564
all.update(countries)
 
565
 
 
566
 
 
567
if __name__ == '__main__':
 
568
    main()