summaryrefslogtreecommitdiffstats
path: root/deluge/plugins/Blocklist/deluge_blocklist/common.py
blob: b45de94b0f038dd99087ec25a8f6f48c1be88059 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# -*- coding: utf-8 -*-
#
# Basic plugin template created by:
# Copyright (C) 2008 Martijn Voncken <mvoncken@gmail.com>
#               2007-2009 Andrew Resch <andrewresch@gmail.com>
#               2009 Damien Churchill <damoxc@gmail.com>
#               2010 Pedro Algarvio <pedro@algarvio.me>
#               2017 Calum Lind <calumlind+deluge@gmail.com>
#
# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
# the additional special exception to link portions of this program with the OpenSSL library.
# See LICENSE for more details.
#

import os.path
from functools import wraps
from sys import exc_info

from pkg_resources import resource_filename


def get_resource(filename):
    return resource_filename(__package__, os.path.join('data', filename))


def raises_errors_as(error):
    """Factory class that returns a decorator which wraps the decorated
    function to raise all exceptions as the specified error type.

    """

    def decorator(func):
        """Returns a function which wraps the given func to raise all exceptions as error."""

        @wraps(func)
        def wrapper(self, *args, **kwargs):
            """Wraps the function in a try..except block and calls it with the specified args.

            Raises:
                Any exceptions as error preserving the message and traceback.

            """
            try:
                return func(self, *args, **kwargs)
            except Exception:
                (value, tb) = exc_info()[1:]
                raise error(value).with_traceback(tb) from None

        return wrapper

    return decorator


def remove_zeros(ip):
    """Removes unneeded zeros from ip addresses.

    Args:
        ip (str): The ip address.

    Returns:
        str: The ip address without the unneeded zeros.

    Example:
        000.000.000.003 -> 0.0.0.3

    """
    return '.'.join([part.lstrip('0').zfill(1) for part in ip.split('.')])


class BadIP(Exception):
    _message = None

    def __init__(self, message):
        super(BadIP, self).__init__(message)

    def __set_message(self, message):
        self._message = message

    def __get_message(self):
        return self._message

    message = property(__get_message, __set_message)
    del __get_message, __set_message


class IP(object):
    __slots__ = ('q1', 'q2', 'q3', 'q4', '_long')

    def __init__(self, q1, q2, q3, q4):
        self.q1 = q1
        self.q2 = q2
        self.q3 = q3
        self.q4 = q4
        self._long = 0
        for q in self.quadrants():
            self._long = (self._long << 8) | int(q)

    @property
    def address(self):
        return '.'.join([str(q) for q in [self.q1, self.q2, self.q3, self.q4]])

    @property
    def long(self):
        return self._long

    @classmethod
    def parse(cls, ip):
        try:
            q1, q2, q3, q4 = [int(q) for q in ip.split('.')]
        except ValueError:
            raise BadIP(_('The IP address "%s" is badly formed' % ip))
        if q1 < 0 or q2 < 0 or q3 < 0 or q4 < 0:
            raise BadIP(_('The IP address "%s" is badly formed' % ip))
        elif q1 > 255 or q2 > 255 or q3 > 255 or q4 > 255:
            raise BadIP(_('The IP address "%s" is badly formed' % ip))
        return cls(q1, q2, q3, q4)

    def quadrants(self):
        return (self.q1, self.q2, self.q3, self.q4)

    #    def next_ip(self):
    #        (q1, q2, q3, q4) = self.quadrants()
    #        if q4 >= 255:
    #            if q3 >= 255:
    #                if q2 >= 255:
    #                    if q1 >= 255:
    #                        raise BadIP(_('There is not a next IP address'))
    #                    q1 += 1
    #                else:
    #                    q2 += 1
    #            else:
    #                q3 += 1
    #        else:
    #            q4 += 1
    #        return IP(q1, q2, q3, q4)
    #
    #    def previous_ip(self):
    #        (q1, q2, q3, q4) = self.quadrants()
    #        if q4 <= 1:
    #            if q3 <= 1:
    #                if q2 <= 1:
    #                    if q1 <= 1:
    #                        raise BadIP(_('There is not a previous IP address'))
    #                    q1 -= 1
    #                else:
    #                    q2 -= 1
    #            else:
    #                q3 -= 1
    #        else:
    #            q4 -= 1
    #        return IP(q1, q2, q3, q4)

    def __lt__(self, other):
        if isinstance(other, ''.__class__):
            other = IP.parse(other)
        return self.long < other.long

    def __gt__(self, other):
        if isinstance(other, ''.__class__):
            other = IP.parse(other)
        return self.long > other.long

    def __eq__(self, other):
        if isinstance(other, ''.__class__):
            other = IP.parse(other)
        return self.long == other.long

    def __repr__(self):
        return '<%s long=%s address="%s">' % (
            self.__class__.__name__,
            self.long,
            self.address,
        )