diff --git a/ckanext/odsh/lib/__init__.py b/ckanext/odsh/lib/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/ckanext/odsh/lib/odsh_icap_client.cfg b/ckanext/odsh/lib/odsh_icap_client.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..654b57a83fc705ebff6769c89035df98f583432a
--- /dev/null
+++ b/ckanext/odsh/lib/odsh_icap_client.cfg
@@ -0,0 +1,9 @@
+[DEFAULT]
+# the IP of the ICAP-Server
+host = 10.61.127.77
+
+# The port of the ICAP-Server
+port = 1344
+
+# the IP of the client-machine
+clientip = 127.0.0.1
diff --git a/ckanext/odsh/lib/odsh_icap_client.py b/ckanext/odsh/lib/odsh_icap_client.py
new file mode 100644
index 0000000000000000000000000000000000000000..d781aafeecab8e7fc8cef34d391207c394d656bb
--- /dev/null
+++ b/ckanext/odsh/lib/odsh_icap_client.py
@@ -0,0 +1,206 @@
+import socket
+import sys
+import time
+import ConfigParser
+
+
+class ODSHICAPRequest(object):
+
+    def __init__(self, FILENAME, FILEBUFF, cfg_file='odsh_icap_client.cfg'):
+        config = ConfigParser.ConfigParser()
+        config.read(cfg_file)
+        self.HOST = '10.61.127.77'
+        self.PORT = 1344
+        self.CLIENTIP = '127.0.0.1'
+        self.FILENAME = FILENAME
+        self.FILEBUFF = FILEBUFF
+
+    def send(self):
+        print("----- Starting ICAP-Request via RESPMOD -----")
+
+        # socket connect
+        try:
+            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        except socket.error as msg:
+            sys.stderr.write("[ERROR] %s\n" % msg[1])
+            sys.exit(1)
+
+        try:
+            sock.connect((self.HOST, self.PORT))
+        except socket.error as msg:
+            sys.stderr.write("[ERROR] %s\n" % msg[1])
+            sys.exit(2)
+
+        # create and send header
+        header = self._get_icap_header(self.FILENAME, self.HOST, self.PORT, self.CLIENTIP).encode()
+        sock.send(header)
+
+        # send file and terminating signal
+        self._sendfile(self.FILEBUFF, sock)
+        sock.send('0\r\n\r\n')
+
+        # fetch and parse the response
+        data_response = self._recvall(sock)
+        response_object = self._parse_response(data_response)
+
+        print("----- Finished ICAP-Request via RESPMOD -----")
+
+        return response_object
+
+    def _get_icap_header(self, fileName, host, port, clientIP):
+        uniqueInt = time.time() # used to generate "unique" int for disabling cache
+    
+        icapRequest = 'RESPMOD' + ' ' + 'icap://' + host + ':' + str(port) + '/RESPMOD' + \
+                      ' ICAP/1.0\r\n' + 'Host: ' + host + ':' + str(port) + '\r\n'
+        icapRequest += 'Allow: 204\r\n'
+        icapRequest += 'X-Client-IP: ' + clientIP + '\r\n'
+    
+        httpRequest = "GET http://" + clientIP + "/" + str(uniqueInt).replace('.', '_') + "/" + \
+                      fileName + ' HTTP/1.1\r\nHost: ' + clientIP + '\r\n\r\n'
+
+        httpResponse = 'HTTP/1.1 200 OK\r\n'
+        httpResponse += 'Transfer-Encoding: chunked\r\n'
+        httpResponse += '\r\n'
+
+        httpRequestLength = len(httpRequest)
+        httpResponseLength = len(httpResponse)
+
+        icapRequest += 'Encapsulated: req-hdr=0, res-hdr=' + str(httpRequestLength) + ', res-body=' + \
+                       str(httpRequestLength + httpResponseLength) + '\r\n\r\n' + httpRequest + httpResponse;
+
+        return icapRequest
+
+    def _sendfile(self, fileBuffer, sock):
+        print('start sending file')
+        PACK_SIZE = 1024 # in bytes
+
+        l = fileBuffer.read(PACK_SIZE)
+        while(l):
+            print('sending %d bytes of data...' % len(l))
+            sock.send('{:02X}'.format(len(l)).encode())
+            sock.send("\r\n".encode())
+            sock.send(l)
+            sock.send("\r\n".encode())
+            l = fileBuffer.read(PACK_SIZE)
+
+    def _sendfile_old(self, fileName, sock):
+        print('start sending file')
+        PACK_SIZE = 1024 # in bytes
+    
+        with open(fileName) as f:
+            l = f.read(PACK_SIZE)
+            while(l):
+                print('sending %d bytes of data...' % len(l))
+                sock.send('{:02X}'.format(len(l)).encode())
+                sock.send("\r\n".encode())
+                sock.send(l)
+                sock.send("\r\n".encode())
+                l = f.read(PACK_SIZE)
+        print('done sending')
+    
+    def _recvall(self, sock):
+        print('receiving response from icap server')
+        BUFF_SIZE = 4096 # 4 KiB
+        data = b''
+        while True:
+            part = sock.recv(BUFF_SIZE)
+            data += part
+            if len(part) < BUFF_SIZE:
+                # either 0 or end of data
+                break
+        return data
+
+    def _parse_response(self, data_response):
+        print('parsing response')
+        lines = data_response.split('\r\n')
+        http_status_code = self._parse_response_http_statuscode(lines)
+        http_block = self._parse_block(lines, 'HTTP/1.1')
+        icap_block = self._parse_block(lines, 'ICAP/1.0')
+
+        response_object = ODSHParsedICAPResponse(data_response, http_status_code, http_block, icap_block)
+        return response_object
+
+    def _parse_response_http_statuscode(self, data_response_lines):
+        http_status_code_found = False
+        http_status_code = None
+        for line in data_response_lines:
+            if line.startswith('HTTP/1.1'):
+                http_status_code = int(line.split(' ')[1]) # example: HTTP/1.1 403 VirusFound
+                http_status_code_found = True
+        
+        if not http_status_code_found:
+            http_status_code = 200 # if no virus is found, no http_status_code is given, defaulting to 200 OK
+        
+        return http_status_code
+
+    def _parse_block(self, data_response_lines, block_start_signal):
+        block_data = None
+        in_block = False
+
+        for line in data_response_lines:
+            if line.startswith(block_start_signal):
+                in_block = True
+                block_data = ''
+            if in_block and not len(line):
+                in_block = False
+                break
+            if in_block:
+                block_data += line + '\r\n'
+
+        return block_data
+            
+
+class ODSHParsedICAPResponse(object):
+
+    def __init__(self, full_response, http_status_code, http_block, icap_block):
+        self.full_response = full_response
+        self.http_status_code = http_status_code
+        self.http_block = http_block
+        self.icap_block = icap_block
+
+    def virus_found(self):
+        if (self.http_status_code != 200) and (self.http_status_code != 403):
+            raise UnknownResponseException('Received an unknown http response code: %d' % self.http_status_code)
+        return self.http_status_code != 200
+
+
+class UnknownResponseException(Exception):
+    pass
+    
+
+def example_print_response(response_object):
+    print('')
+    print('Example output of response_object:')
+    print('')
+
+    #print('Full ICAP-Response: ')
+    #print(response_object.full_response)
+    #print('')
+
+    print('HTTP-Status-Code (explicit or implied):')
+    print(response_object.http_status_code)
+    print('')
+    
+    print('HTTP-Block:')
+    print(response_object.http_block)
+    print('')
+
+    print('ICAP-Block:')
+    print(response_object.icap_block)
+    print('')
+
+    print('Virus found?')
+    print(response_object.virus_found())
+    print('')
+
+        
+if __name__ == "__main__":
+
+    # example file with virus
+    FILENAME = 'test_files/eicar.txt'
+
+    # example file without virus
+    #FILENAME = 'test_files/lorem-ipsum.pdf'
+
+    odsh_parsed_icap_response = ODSHICAPRequest(FILENAME).send()
+    example_print_response(odsh_parsed_icap_response)
diff --git a/ckanext/odsh/lib/uploader.py b/ckanext/odsh/lib/uploader.py
new file mode 100644
index 0000000000000000000000000000000000000000..21558bd2218ce45b61e71835d64f918c50ea56a1
--- /dev/null
+++ b/ckanext/odsh/lib/uploader.py
@@ -0,0 +1,21 @@
+import ckan.logic as logic
+from ckan.lib.uploader import ResourceUpload
+from odsh_icap_client import ODSHICAPRequest
+
+import logging
+
+log = logging.getLogger(__name__)
+
+ValidationError = logic.ValidationError
+
+class ODSHResourceUpload(ResourceUpload):
+
+    def __init__(self, resource):
+        super(ODSHResourceUpload, self).__init__(resource)
+        if self._icap_virus_found():
+            raise ValidationError(['Virus gefunden'])
+        
+    def _icap_virus_found(self):
+        response_object = ODSHICAPRequest(self.filename, self.upload_file).send()
+        return response_object.virus_found()
+        
diff --git a/ckanext/odsh/plugin.py b/ckanext/odsh/plugin.py
index eb1454f99b43c5b63efe939d7865cd07273a43d0..1a525e5779f5e6fb4ce862e6153c282eb2104243 100644
--- a/ckanext/odsh/plugin.py
+++ b/ckanext/odsh/plugin.py
@@ -4,6 +4,7 @@ import ckan.plugins.toolkit as toolkit
 from ckan.lib.plugins import DefaultTranslation
 from ckan.lib.plugins import DefaultDatasetForm
 from ckan.common import OrderedDict
+from ckanext.odsh.lib.uploader import ODSHResourceUpload
 import ckan.lib.helpers as helpers
 import helpers as odsh_helpers
 from routes.mapper import SubMapper
@@ -61,6 +62,13 @@ def odsh_group_id_selected(selected, group_id):
     return False
 
 
+class OdshIcapPlugin(plugins.SingletonPlugin):
+    plugins.implements(plugins.IUploader, inherit=True)
+
+    def get_resource_uploader(self, data_dict):
+        return ODSHResourceUpload(data_dict)
+
+
 class OdshPlugin(plugins.SingletonPlugin, DefaultTranslation, DefaultDatasetForm):
     plugins.implements(plugins.IConfigurer)
     plugins.implements(plugins.ITemplateHelpers)
diff --git a/setup.py b/setup.py
index 68cb9f7d10456a451ee9250ca59c8f2a8037038f..22cb91a1d3710cef8488e3945616f7bcbc0d6562 100755
--- a/setup.py
+++ b/setup.py
@@ -81,12 +81,13 @@ setup(
     entry_points='''
         [ckan.plugins]
         odsh=ckanext.odsh.plugin:OdshPlugin
+        odsh_icap=ckanext.odsh.plugin:OdshIcapPlugin
         statistikamtnord_harvester=ckanext.odsh.harvesters:StatistikamtNordHarvester
         kiel_harvester=ckanext.odsh.harvesters:KielHarvester
-        
+
         [paste.paster_command]
         odsh_initialization = ckanext.odsh.commands.initialization:Initialization
-        
+
         [babel.extractors]
         ckan = ckan.lib.extract:extract_ckan
     ''',