17db96d56Sopenharmony_ci/*
27db96d56Sopenharmony_ci * Helper method for urllib to fetch the proxy configuration settings
37db96d56Sopenharmony_ci * using the SystemConfiguration framework.
47db96d56Sopenharmony_ci */
57db96d56Sopenharmony_ci#include <Python.h>
67db96d56Sopenharmony_ci#include <SystemConfiguration/SystemConfiguration.h>
77db96d56Sopenharmony_ci
87db96d56Sopenharmony_cistatic int32_t
97db96d56Sopenharmony_cicfnum_to_int32(CFNumberRef num)
107db96d56Sopenharmony_ci{
117db96d56Sopenharmony_ci    int32_t result;
127db96d56Sopenharmony_ci
137db96d56Sopenharmony_ci    CFNumberGetValue(num, kCFNumberSInt32Type, &result);
147db96d56Sopenharmony_ci    return result;
157db96d56Sopenharmony_ci}
167db96d56Sopenharmony_ci
177db96d56Sopenharmony_cistatic PyObject*
187db96d56Sopenharmony_cicfstring_to_pystring(CFStringRef ref)
197db96d56Sopenharmony_ci{
207db96d56Sopenharmony_ci    const char* s;
217db96d56Sopenharmony_ci
227db96d56Sopenharmony_ci    s = CFStringGetCStringPtr(ref, kCFStringEncodingUTF8);
237db96d56Sopenharmony_ci    if (s) {
247db96d56Sopenharmony_ci        return PyUnicode_DecodeUTF8(
257db96d56Sopenharmony_ci                        s, strlen(s), NULL);
267db96d56Sopenharmony_ci
277db96d56Sopenharmony_ci    } else {
287db96d56Sopenharmony_ci        CFIndex len = CFStringGetLength(ref);
297db96d56Sopenharmony_ci        Boolean ok;
307db96d56Sopenharmony_ci        PyObject* result;
317db96d56Sopenharmony_ci        char* buf;
327db96d56Sopenharmony_ci
337db96d56Sopenharmony_ci        buf = PyMem_Malloc(len*4);
347db96d56Sopenharmony_ci        if (buf == NULL) {
357db96d56Sopenharmony_ci            PyErr_NoMemory();
367db96d56Sopenharmony_ci            return NULL;
377db96d56Sopenharmony_ci        }
387db96d56Sopenharmony_ci
397db96d56Sopenharmony_ci        ok = CFStringGetCString(ref,
407db96d56Sopenharmony_ci                        buf, len * 4,
417db96d56Sopenharmony_ci                        kCFStringEncodingUTF8);
427db96d56Sopenharmony_ci        if (!ok) {
437db96d56Sopenharmony_ci            PyMem_Free(buf);
447db96d56Sopenharmony_ci            return NULL;
457db96d56Sopenharmony_ci        } else {
467db96d56Sopenharmony_ci            result = PyUnicode_DecodeUTF8(
477db96d56Sopenharmony_ci                            buf, strlen(buf), NULL);
487db96d56Sopenharmony_ci            PyMem_Free(buf);
497db96d56Sopenharmony_ci        }
507db96d56Sopenharmony_ci        return result;
517db96d56Sopenharmony_ci    }
527db96d56Sopenharmony_ci}
537db96d56Sopenharmony_ci
547db96d56Sopenharmony_ci
557db96d56Sopenharmony_cistatic PyObject*
567db96d56Sopenharmony_ciget_proxy_settings(PyObject* Py_UNUSED(mod), PyObject *Py_UNUSED(ignored))
577db96d56Sopenharmony_ci{
587db96d56Sopenharmony_ci    CFDictionaryRef proxyDict = NULL;
597db96d56Sopenharmony_ci    CFNumberRef aNum = NULL;
607db96d56Sopenharmony_ci    CFArrayRef anArray = NULL;
617db96d56Sopenharmony_ci    PyObject* result = NULL;
627db96d56Sopenharmony_ci    PyObject* v;
637db96d56Sopenharmony_ci    int r;
647db96d56Sopenharmony_ci
657db96d56Sopenharmony_ci    Py_BEGIN_ALLOW_THREADS
667db96d56Sopenharmony_ci    proxyDict = SCDynamicStoreCopyProxies(NULL);
677db96d56Sopenharmony_ci    Py_END_ALLOW_THREADS
687db96d56Sopenharmony_ci
697db96d56Sopenharmony_ci    if (!proxyDict) {
707db96d56Sopenharmony_ci        Py_RETURN_NONE;
717db96d56Sopenharmony_ci    }
727db96d56Sopenharmony_ci
737db96d56Sopenharmony_ci    result = PyDict_New();
747db96d56Sopenharmony_ci    if (result == NULL) goto error;
757db96d56Sopenharmony_ci
767db96d56Sopenharmony_ci    aNum = CFDictionaryGetValue(proxyDict,
777db96d56Sopenharmony_ci        kSCPropNetProxiesExcludeSimpleHostnames);
787db96d56Sopenharmony_ci    if (aNum == NULL) {
797db96d56Sopenharmony_ci        v = PyBool_FromLong(0);
807db96d56Sopenharmony_ci    } else {
817db96d56Sopenharmony_ci        v = PyBool_FromLong(cfnum_to_int32(aNum));
827db96d56Sopenharmony_ci    }
837db96d56Sopenharmony_ci
847db96d56Sopenharmony_ci    if (v == NULL) goto error;
857db96d56Sopenharmony_ci
867db96d56Sopenharmony_ci    r = PyDict_SetItemString(result, "exclude_simple", v);
877db96d56Sopenharmony_ci    Py_DECREF(v); v = NULL;
887db96d56Sopenharmony_ci    if (r == -1) goto error;
897db96d56Sopenharmony_ci
907db96d56Sopenharmony_ci    anArray = CFDictionaryGetValue(proxyDict,
917db96d56Sopenharmony_ci                    kSCPropNetProxiesExceptionsList);
927db96d56Sopenharmony_ci    if (anArray != NULL) {
937db96d56Sopenharmony_ci        CFIndex len = CFArrayGetCount(anArray);
947db96d56Sopenharmony_ci        CFIndex i;
957db96d56Sopenharmony_ci        v = PyTuple_New(len);
967db96d56Sopenharmony_ci        if (v == NULL) goto error;
977db96d56Sopenharmony_ci
987db96d56Sopenharmony_ci        r = PyDict_SetItemString(result, "exceptions", v);
997db96d56Sopenharmony_ci        Py_DECREF(v);
1007db96d56Sopenharmony_ci        if (r == -1) goto error;
1017db96d56Sopenharmony_ci
1027db96d56Sopenharmony_ci        for (i = 0; i < len; i++) {
1037db96d56Sopenharmony_ci            CFStringRef aString = NULL;
1047db96d56Sopenharmony_ci
1057db96d56Sopenharmony_ci            aString = CFArrayGetValueAtIndex(anArray, i);
1067db96d56Sopenharmony_ci            if (aString == NULL) {
1077db96d56Sopenharmony_ci                PyTuple_SetItem(v, i, Py_None);
1087db96d56Sopenharmony_ci                Py_INCREF(Py_None);
1097db96d56Sopenharmony_ci            } else {
1107db96d56Sopenharmony_ci                PyObject* t = cfstring_to_pystring(aString);
1117db96d56Sopenharmony_ci                if (!t) {
1127db96d56Sopenharmony_ci                    PyTuple_SetItem(v, i, Py_None);
1137db96d56Sopenharmony_ci                    Py_INCREF(Py_None);
1147db96d56Sopenharmony_ci                } else {
1157db96d56Sopenharmony_ci                    PyTuple_SetItem(v, i, t);
1167db96d56Sopenharmony_ci                }
1177db96d56Sopenharmony_ci            }
1187db96d56Sopenharmony_ci        }
1197db96d56Sopenharmony_ci    }
1207db96d56Sopenharmony_ci
1217db96d56Sopenharmony_ci    CFRelease(proxyDict);
1227db96d56Sopenharmony_ci    return result;
1237db96d56Sopenharmony_ci
1247db96d56Sopenharmony_cierror:
1257db96d56Sopenharmony_ci    if (proxyDict)  CFRelease(proxyDict);
1267db96d56Sopenharmony_ci    Py_XDECREF(result);
1277db96d56Sopenharmony_ci    return NULL;
1287db96d56Sopenharmony_ci}
1297db96d56Sopenharmony_ci
1307db96d56Sopenharmony_cistatic int
1317db96d56Sopenharmony_ciset_proxy(PyObject* proxies, const char* proto, CFDictionaryRef proxyDict,
1327db96d56Sopenharmony_ci                CFStringRef enabledKey,
1337db96d56Sopenharmony_ci                CFStringRef hostKey, CFStringRef portKey)
1347db96d56Sopenharmony_ci{
1357db96d56Sopenharmony_ci    CFNumberRef aNum;
1367db96d56Sopenharmony_ci
1377db96d56Sopenharmony_ci    aNum = CFDictionaryGetValue(proxyDict, enabledKey);
1387db96d56Sopenharmony_ci    if (aNum && cfnum_to_int32(aNum)) {
1397db96d56Sopenharmony_ci        CFStringRef hostString;
1407db96d56Sopenharmony_ci
1417db96d56Sopenharmony_ci        hostString = CFDictionaryGetValue(proxyDict, hostKey);
1427db96d56Sopenharmony_ci        aNum = CFDictionaryGetValue(proxyDict, portKey);
1437db96d56Sopenharmony_ci
1447db96d56Sopenharmony_ci        if (hostString) {
1457db96d56Sopenharmony_ci            int r;
1467db96d56Sopenharmony_ci            PyObject* h = cfstring_to_pystring(hostString);
1477db96d56Sopenharmony_ci            PyObject* v;
1487db96d56Sopenharmony_ci            if (h) {
1497db96d56Sopenharmony_ci                if (aNum) {
1507db96d56Sopenharmony_ci                    int32_t port = cfnum_to_int32(aNum);
1517db96d56Sopenharmony_ci                    v = PyUnicode_FromFormat("http://%U:%ld",
1527db96d56Sopenharmony_ci                        h, (long)port);
1537db96d56Sopenharmony_ci                } else {
1547db96d56Sopenharmony_ci                    v = PyUnicode_FromFormat("http://%U", h);
1557db96d56Sopenharmony_ci                }
1567db96d56Sopenharmony_ci                Py_DECREF(h);
1577db96d56Sopenharmony_ci                if (!v) return -1;
1587db96d56Sopenharmony_ci                r = PyDict_SetItemString(proxies, proto,
1597db96d56Sopenharmony_ci                    v);
1607db96d56Sopenharmony_ci                Py_DECREF(v);
1617db96d56Sopenharmony_ci                return r;
1627db96d56Sopenharmony_ci            }
1637db96d56Sopenharmony_ci        }
1647db96d56Sopenharmony_ci
1657db96d56Sopenharmony_ci    }
1667db96d56Sopenharmony_ci    return 0;
1677db96d56Sopenharmony_ci}
1687db96d56Sopenharmony_ci
1697db96d56Sopenharmony_ci
1707db96d56Sopenharmony_ci
1717db96d56Sopenharmony_cistatic PyObject*
1727db96d56Sopenharmony_ciget_proxies(PyObject* Py_UNUSED(mod), PyObject *Py_UNUSED(ignored))
1737db96d56Sopenharmony_ci{
1747db96d56Sopenharmony_ci    PyObject* result = NULL;
1757db96d56Sopenharmony_ci    int r;
1767db96d56Sopenharmony_ci    CFDictionaryRef proxyDict = NULL;
1777db96d56Sopenharmony_ci
1787db96d56Sopenharmony_ci    Py_BEGIN_ALLOW_THREADS
1797db96d56Sopenharmony_ci    proxyDict = SCDynamicStoreCopyProxies(NULL);
1807db96d56Sopenharmony_ci    Py_END_ALLOW_THREADS
1817db96d56Sopenharmony_ci
1827db96d56Sopenharmony_ci    if (proxyDict == NULL) {
1837db96d56Sopenharmony_ci        return PyDict_New();
1847db96d56Sopenharmony_ci    }
1857db96d56Sopenharmony_ci
1867db96d56Sopenharmony_ci    result = PyDict_New();
1877db96d56Sopenharmony_ci    if (result == NULL) goto error;
1887db96d56Sopenharmony_ci
1897db96d56Sopenharmony_ci    r = set_proxy(result, "http", proxyDict,
1907db96d56Sopenharmony_ci        kSCPropNetProxiesHTTPEnable,
1917db96d56Sopenharmony_ci        kSCPropNetProxiesHTTPProxy,
1927db96d56Sopenharmony_ci        kSCPropNetProxiesHTTPPort);
1937db96d56Sopenharmony_ci    if (r == -1) goto error;
1947db96d56Sopenharmony_ci    r = set_proxy(result, "https", proxyDict,
1957db96d56Sopenharmony_ci        kSCPropNetProxiesHTTPSEnable,
1967db96d56Sopenharmony_ci        kSCPropNetProxiesHTTPSProxy,
1977db96d56Sopenharmony_ci        kSCPropNetProxiesHTTPSPort);
1987db96d56Sopenharmony_ci    if (r == -1) goto error;
1997db96d56Sopenharmony_ci    r = set_proxy(result, "ftp", proxyDict,
2007db96d56Sopenharmony_ci        kSCPropNetProxiesFTPEnable,
2017db96d56Sopenharmony_ci        kSCPropNetProxiesFTPProxy,
2027db96d56Sopenharmony_ci        kSCPropNetProxiesFTPPort);
2037db96d56Sopenharmony_ci    if (r == -1) goto error;
2047db96d56Sopenharmony_ci    r = set_proxy(result, "gopher", proxyDict,
2057db96d56Sopenharmony_ci        kSCPropNetProxiesGopherEnable,
2067db96d56Sopenharmony_ci        kSCPropNetProxiesGopherProxy,
2077db96d56Sopenharmony_ci        kSCPropNetProxiesGopherPort);
2087db96d56Sopenharmony_ci    if (r == -1) goto error;
2097db96d56Sopenharmony_ci
2107db96d56Sopenharmony_ci    CFRelease(proxyDict);
2117db96d56Sopenharmony_ci    return result;
2127db96d56Sopenharmony_cierror:
2137db96d56Sopenharmony_ci    if (proxyDict)  CFRelease(proxyDict);
2147db96d56Sopenharmony_ci    Py_XDECREF(result);
2157db96d56Sopenharmony_ci    return NULL;
2167db96d56Sopenharmony_ci}
2177db96d56Sopenharmony_ci
2187db96d56Sopenharmony_cistatic PyMethodDef mod_methods[] = {
2197db96d56Sopenharmony_ci    {
2207db96d56Sopenharmony_ci        "_get_proxy_settings",
2217db96d56Sopenharmony_ci        get_proxy_settings,
2227db96d56Sopenharmony_ci        METH_NOARGS,
2237db96d56Sopenharmony_ci        NULL,
2247db96d56Sopenharmony_ci    },
2257db96d56Sopenharmony_ci    {
2267db96d56Sopenharmony_ci        "_get_proxies",
2277db96d56Sopenharmony_ci        get_proxies,
2287db96d56Sopenharmony_ci        METH_NOARGS,
2297db96d56Sopenharmony_ci        NULL,
2307db96d56Sopenharmony_ci    },
2317db96d56Sopenharmony_ci    { 0, 0, 0, 0 }
2327db96d56Sopenharmony_ci};
2337db96d56Sopenharmony_ci
2347db96d56Sopenharmony_cistatic PyModuleDef_Slot _scproxy_slots[] = {
2357db96d56Sopenharmony_ci    {0, NULL}
2367db96d56Sopenharmony_ci};
2377db96d56Sopenharmony_ci
2387db96d56Sopenharmony_cistatic struct PyModuleDef _scproxy_module = {
2397db96d56Sopenharmony_ci    PyModuleDef_HEAD_INIT,
2407db96d56Sopenharmony_ci    .m_name = "_scproxy",
2417db96d56Sopenharmony_ci    .m_size = 0,
2427db96d56Sopenharmony_ci    .m_methods = mod_methods,
2437db96d56Sopenharmony_ci    .m_slots = _scproxy_slots,
2447db96d56Sopenharmony_ci};
2457db96d56Sopenharmony_ci
2467db96d56Sopenharmony_ci#ifdef __cplusplus
2477db96d56Sopenharmony_ciextern "C" {
2487db96d56Sopenharmony_ci#endif
2497db96d56Sopenharmony_ci
2507db96d56Sopenharmony_ciPyMODINIT_FUNC
2517db96d56Sopenharmony_ciPyInit__scproxy(void)
2527db96d56Sopenharmony_ci{
2537db96d56Sopenharmony_ci    return PyModuleDef_Init(&_scproxy_module);
2547db96d56Sopenharmony_ci}
2557db96d56Sopenharmony_ci
2567db96d56Sopenharmony_ci#ifdef __cplusplus
2577db96d56Sopenharmony_ci}
2587db96d56Sopenharmony_ci#endif
259