<commit_before>"""
Apple Push Notification Service
"""

import codecs
import json
import ssl
import struct
import socket
import time
from contextlib import closing
from binascii import unhexlify

from django.core.exceptions import ImproperlyConfigured
from ..exceptions import (
    APNSServerError,
    APNSDataOverflow,
)
from ..settings import INSTAPUSH_SETTINGS as settings


SETTINGS = settings.get('APNS_SETTINGS')


def _apns_create_socket(address_tuple, **kwargs):
    certfile = kwargs.get('certfile') or SETTINGS.get("APNS_CERTIFICATE")
    if not certfile:
        raise ImproperlyConfigured(
            'You need to set PUSH_NOTIFICATIONS_SETTINGS["APNS_CERTIFICATE"] to send messages through APNS.'
        )

    try:
        with open(certfile, "r") as f:
            f.read()
    except Exception as e:
        raise ImproperlyConfigured("The APNS certificate file at %r is not readable: %s" % (certfile, e))

    ca_certs = SETTINGS.get("APNS_CA_CERTIFICATES")

    sock = socket.socket()
    sock = ssl.wrap_socket(sock, ssl_version=ssl.PROTOCOL_TLSv1, certfile=certfile, ca_certs=ca_certs)
    sock.connect(address_tuple)

    return sock


def _apns_create_socket_to_push(**kwargs):
    return _apns_create_socket((SETTINGS["HOST"], SETTINGS["PORT"]), **kwargs)


def _apns_create_socket_to_feedback():
    return _apns_create_socket((SETTINGS["FEEDBACK_HOST"], SETTINGS["FEEDBACK_PORT"]))


def _apns_pack_frame(token_hex, payload, identifier, expiration, priority):
    token = unhexlify(token_hex)
    # |COMMAND|FRAME-LEN|{token}|{payload}|{id:4}|{expiration:4}|{priority:1}
    frame_len = 3 * 5 + len(token) + len(payload) + 4 + 4 + 1  # 5 items, each 3 bytes prefix, then each item length
    frame_fmt = "!BIBH%ssBH%ssBHIBHIBHB" % (len(token), len(payload))
    frame = struct.pack(
        frame_fmt,
        2, frame_len,
        1, len(token), token,
        2, len(payload), payload,
        3, 4, identifier,
        4, 4, expiration,
        5, 1, priority)

    return frame


def _apns_check_errors(sock):
    timeout = SETTINGS["ERROR_TIMEOUT"]
    if timeout is None:
        return  # assume everything went fine!
    saved_timeout = sock.gettimeout()
    try:
        sock.settimeout(timeout)
        data = sock.recv(6)
        if data:
            command, status, identifier = struct.unpack("!BBI", data)
            # apple protocol says command is always 8. See http://goo.gl/ENUjXg
            assert command == 8, "Command must be 8!"
            if status != 0:
                raise APNSServerError(status, identifier)
    except socket.timeout:  # py3, see http://bugs.python.org/issue10272
        pass
    except ssl.SSLError as e:  # py2
        if "timed out" not in e.message:
            raise
    finally:
        sock.settimeout(saved_timeout)


def _apns_send(token, alert, badge=None, sound="default", category=None, content_available=True,
    action_loc_key=None, loc_key=None, loc_args=[], extra={}, identifier=0,
    expiration=None, priority=10, socket=None, **kwargs):
    data = {}
    aps_data = {}

    custom_params = alert
    alert = custom_params.pop('message')

    if action_loc_key or loc_key or loc_args:
        alert = {"body": alert} if alert else {}
        if action_loc_key:
            alert["action-loc-key"] = action_loc_key
        if loc_key:
            alert["loc-key"] = loc_key
        if loc_args:
            alert["loc-args"] = loc_args

    if alert is not None:
        aps_data["alert"] = alert

    if badge is not None:
        aps_data["badge"] = badge

    if sound is not None:
        aps_data["sound"] = sound
<commit_msg>Added missing title-loc-key and title-loc-args arguments to _apns_send<commit_after>"""
Apple Push Notification Service
"""

import codecs
import json
import ssl
import struct
import socket
import time
from contextlib import closing
from binascii import unhexlify

from django.core.exceptions import ImproperlyConfigured
from ..exceptions import (
    APNSServerError,
    APNSDataOverflow,
)
from ..settings import INSTAPUSH_SETTINGS as settings


SETTINGS = settings.get('APNS_SETTINGS')


def _apns_create_socket(address_tuple, **kwargs):
    certfile = kwargs.get('certfile') or SETTINGS.get("APNS_CERTIFICATE")
    if not certfile:
        raise ImproperlyConfigured(
            'You need to set PUSH_NOTIFICATIONS_SETTINGS["APNS_CERTIFICATE"] to send messages through APNS.'
        )

    try:
        with open(certfile, "r") as f:
            f.read()
    except Exception as e:
        raise ImproperlyConfigured("The APNS certificate file at %r is not readable: %s" % (certfile, e))

    ca_certs = SETTINGS.get("APNS_CA_CERTIFICATES")

    sock = socket.socket()
    sock = ssl.wrap_socket(sock, ssl_version=ssl.PROTOCOL_TLSv1, certfile=certfile, ca_certs=ca_certs)
    sock.connect(address_tuple)

    return sock


def _apns_create_socket_to_push(**kwargs):
    return _apns_create_socket((SETTINGS["HOST"], SETTINGS["PORT"]), **kwargs)


def _apns_create_socket_to_feedback():
    return _apns_create_socket((SETTINGS["FEEDBACK_HOST"], SETTINGS["FEEDBACK_PORT"]))


def _apns_pack_frame(token_hex, payload, identifier, expiration, priority):
    token = unhexlify(token_hex)
    # |COMMAND|FRAME-LEN|{token}|{payload}|{id:4}|{expiration:4}|{priority:1}
    frame_len = 3 * 5 + len(token) + len(payload) + 4 + 4 + 1  # 5 items, each 3 bytes prefix, then each item length
    frame_fmt = "!BIBH%ssBH%ssBHIBHIBHB" % (len(token), len(payload))
    frame = struct.pack(
        frame_fmt,
        2, frame_len,
        1, len(token), token,
        2, len(payload), payload,
        3, 4, identifier,
        4, 4, expiration,
        5, 1, priority)

    return frame


def _apns_check_errors(sock):
    timeout = SETTINGS["ERROR_TIMEOUT"]
    if timeout is None:
        return  # assume everything went fine!
    saved_timeout = sock.gettimeout()
    try:
        sock.settimeout(timeout)
        data = sock.recv(6)
        if data:
            command, status, identifier = struct.unpack("!BBI", data)
            # apple protocol says command is always 8. See http://goo.gl/ENUjXg
            assert command == 8, "Command must be 8!"
            if status != 0:
                raise APNSServerError(status, identifier)
    except socket.timeout:  # py3, see http://bugs.python.org/issue10272
        pass
    except ssl.SSLError as e:  # py2
        if "timed out" not in e.message:
            raise
    finally:
        sock.settimeout(saved_timeout)


def _apns_send(token, alert, badge=None, sound="default", category=None, content_available=True,
    action_loc_key=None, loc_key=None, loc_args=[], title_loc_key=None, title_loc_args=None,
    extra={}, identifier=0, expiration=None, priority=10, socket=None, **kwargs):
    data = {}
    aps_data = {}

    custom_params = alert
    alert = custom_params.pop('message', '')

    if action_loc_key or loc_key or loc_args:
        alert = {"body": alert} if alert else {}
        if action_loc_key:
            alert["action-loc-key"] = action_loc_key
        if loc_key:
            alert["loc-key"] = loc_key
        if loc_args:
            alert["loc-args"] = loc_args

    if title_loc_key:
        alert['title_loc_key'] = title_loc_key

    if title_loc_args:
        alert['title_loc_args'] = title_loc_args

    if alert is not None:
        aps_data["alert"] = alert

    if badge is not None:
        aps_data["badge"] = badge

    if sound is not None:
        aps_data["sound"] = sound

{'fraction_non_alphanumeric': 0.10785228636181843, 'fraction_numerical': 0.009332089054792695, 'mean_word_length': 3.0661246612466124, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1741623', 'n_tokens_mistral': 2529, 'n_tokens_neox': 2415, 'n_words': 615}