1# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
2
3# Copyright (C) 2003-2017 Nominum, Inc.
4#
5# Permission to use, copy, modify, and distribute this software and its
6# documentation for any purpose with or without fee is hereby granted,
7# provided that the above copyright notice and this permission notice
8# appear in all copies.
9#
10# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
11# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
13# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
16# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18"""DNS TTL conversion."""
19
20import dns.exception
21
22MAX_TTL = 2147483647
23
24class BadTTL(dns.exception.SyntaxError):
25    """DNS TTL value is not well-formed."""
26
27
28def from_text(text):
29    """Convert the text form of a TTL to an integer.
30
31    The BIND 8 units syntax for TTLs (e.g. '1w6d4h3m10s') is supported.
32
33    *text*, a ``str``, the textual TTL.
34
35    Raises ``dns.ttl.BadTTL`` if the TTL is not well-formed.
36
37    Returns an ``int``.
38    """
39
40    if text.isdigit():
41        total = int(text)
42    elif len(text) == 0:
43        raise BadTTL
44    else:
45        total = 0
46        current = 0
47        need_digit = True
48        for c in text:
49            if c.isdigit():
50                current *= 10
51                current += int(c)
52                need_digit = False
53            else:
54                if need_digit:
55                    raise BadTTL
56                c = c.lower()
57                if c == 'w':
58                    total += current * 604800
59                elif c == 'd':
60                    total += current * 86400
61                elif c == 'h':
62                    total += current * 3600
63                elif c == 'm':
64                    total += current * 60
65                elif c == 's':
66                    total += current
67                else:
68                    raise BadTTL("unknown unit '%s'" % c)
69                current = 0
70                need_digit = True
71        if not current == 0:
72            raise BadTTL("trailing integer")
73    if total < 0 or total > MAX_TTL:
74        raise BadTTL("TTL should be between 0 and 2^31 - 1 (inclusive)")
75    return total
76
77
78def make(value):
79    if isinstance(value, int):
80        return value
81    elif isinstance(value, str):
82        return dns.ttl.from_text(value)
83    else:
84        raise ValueError('cannot convert value to TTL')
85