├── README.rst └── nfwx /README.rst: -------------------------------------------------------------------------------- 1 | ============================== 2 | NFWX - Nokia Firmware Explorer 3 | ============================== 4 | 5 | .. important:: 6 | 7 | As of April 2013 this tool does *not* work anymore. Nokia `has 8 | closed the access to their firmware download service`__ and it 9 | keeps failing with HTTP 500 status codes. Nevertheless, the 10 | code for ``nfwx`` will remain publicly available. 11 | 12 | __ http://www.allaboutsymbian.com/flow/item/17340_Nokia_news_shorts_Navifirm_acc.php 13 | 14 | NFWX is a small command-line tool to explore the available firmware 15 | downloads for Nokia devices, which can be obtained using the same 16 | SOAP services as used by the Nokia-supplied tools to install the 17 | updates. 18 | 19 | 20 | Disclaimers 21 | =========== 22 | 23 | * This software **does not download any firmware/software from the Nokia 24 | servers**. It just provides a listing of what's available and the URLs 25 | to files. 26 | 27 | * The software **is provided as-is, without warranty of any kind**. 28 | The author is not responsible for any damage which may be caused to 29 | your phone due to the incorrect usage of it. 30 | 31 | * It is **recommended** to use the `official update procedures`__ for 32 | your Nokia devices. 33 | 34 | __ http://www.nokia.com/global/support/software-update/update-your-phone/ 35 | 36 | 37 | Requirements 38 | ============ 39 | 40 | This tool is written in Python_, and uses the SOAPpy_ library. 41 | 42 | .. _python: http://www.python.org 43 | .. _soappy: https://github.com/tarequeh/SOAPpy 44 | 45 | 46 | Usage 47 | ===== 48 | 49 | Make sure you have Python_ and SOAPpy_ installed, then you can run the 50 | tool in interactive mode (which is faster). It will show a ``(nfwx)`` 51 | prompt, where you can enter commands:: 52 | 53 | % ./nfwx 54 | (nfwx) _ 55 | 56 | To get information about a particular command, use ``help``:: 57 | 58 | (nfwx) help products 59 | List product-ids and their names. 60 | 61 | Alternatively, commands can be entered directly from the shell when 62 | invoking ``nfwx``:: 63 | 64 | $ ./nfwx products > productlist.txt 65 | 66 | 67 | Tips and tricks 68 | =============== 69 | 70 | It is possible to pass a string to search inside the products list:: 71 | 72 | (nfwx) products N9 73 | xxxxxxxxxx Nokia N97 mini 74 | yyyyyyyyyy Nokia N9 75 | ... 76 | 77 | For scripting purposes, it is possible to define the environment variable 78 | ``NFWX_SID`` to the output of the ``sid`` command, to avoid each invocation 79 | requesting a new session identifier to the web service:: 80 | 81 | % export NFWX_SID=$(./nfwx sid) 82 | % ./nfwx variants 123456789 83 | ... 84 | % ./nfwx releases 666999666 85 | ... 86 | 87 | 88 | How do I flash my device? 89 | ========================= 90 | 91 | `Ask somewhere else`__. Seriously. 92 | 93 | __ http://lmgtfy.com/?q=how+to+flash+a+nokia+phone 94 | 95 | 96 | License 97 | ======= 98 | 99 | This software is distributed under the terms of the `MIT license`__. 100 | 101 | __ http://opensource.org/licenses/mit-license.php 102 | 103 | -------------------------------------------------------------------------------- /nfwx: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # vim:fenc=utf-8 4 | # 5 | # Copyright © 2012 Adrian Perez 6 | # 7 | # Distributed under terms of the MIT license. 8 | 9 | from SOAPpy.Parser import parseSOAP 10 | import httplib 11 | import os, cmd 12 | 13 | 14 | try: 15 | URL_INDEX = int(os.environ.get("NFWX_URL_INDEX", "0", 10)) 16 | except: 17 | URL_INDEX = 0 18 | 19 | URLS = ( 20 | ('https://www.caresuite.nokia.com/caresuite/get_params.do?application_id=2', 21 | 'www.caresuite.nokia.com', '/caresuite/CareSuite?WSDL'), 22 | ('https://www.dsut.online.nokia.com/oti/get_params.do?application_id=2', 23 | 'www.dsut.online.nokia.com', '/oti/CareSuite?WSDL'), 24 | ('https://www.dsut-qa.online.nokia.com/oti/get_params.do?application_id=2', 25 | 'www.dsut-qa.online.nokia.com', '/oti/CareSuite?WSDL'), 26 | ) 27 | 28 | def getSid(): 29 | from urllib import urlopen 30 | resp = urlopen(URLS[URL_INDEX][0]) 31 | sid = resp.headers["set-cookie"] 32 | assert sid.startswith("JSESSIONID=") 33 | return sid.split(";")[0][11:] 34 | 35 | SID = os.environ.get("NFWX_SID", None) 36 | if SID is None: 37 | SID = getSid() 38 | 39 | SOAP_TEMPLATE = """\ 40 | 41 | 48 | 49 | 50 | %(soapPayload)s 51 | 52 | 53 | """ 54 | 55 | # (MethodName, ResponseAttributeName, PayloadTemplate) 56 | SOAP_GET_PRODUCT_LIST = ( 57 | "GetProductList", 58 | "GetProductListResponse", 59 | """\ 60 | %(sid)s 61 | 62 | """) 63 | SOAP_GET_RELEASES_FOR_PRODUCT = ( 64 | "GetReleasesForProduct", 65 | "GetReleasesForProductResponse", 66 | """\ 67 | %(sid)s 68 | %(productId)i 69 | """) 70 | SOAP_GET_RELEASE_VARIANTS = ( 71 | "GetReleaseVariants", 72 | "GetReleaseVariantsResponse", 73 | """\ 74 | %(sid)s 75 | %(releaseId)i 76 | """) 77 | 78 | def soapRequest(soap, **args): 79 | body = SOAP_TEMPLATE % dict(soapMethodName = soap[0], 80 | soapPayload = soap[2] % args) 81 | conn = httplib.HTTPSConnection(URLS[URL_INDEX][1]) 82 | conn.request("POST", URLS[URL_INDEX][2], body, {"Content-Type": "text/xml"}) 83 | resp = conn.getresponse() 84 | if resp.status != 200: 85 | raise Exception("HTTP response %i" % resp.status) 86 | rval = getattr(parseSOAP(resp.read()), soap[1]).result 87 | resp.close() 88 | conn.close() 89 | return rval 90 | 91 | 92 | _PRODUCT_LIST = None 93 | def getProductList(): 94 | global _PRODUCT_LIST 95 | if _PRODUCT_LIST is None: 96 | _PRODUCT_LIST = soapRequest(SOAP_GET_PRODUCT_LIST, sid=SID) 97 | return _PRODUCT_LIST 98 | 99 | _RELEASES_FOR_PRODUCT = {} 100 | def getReleasesForProduct(productId): 101 | global _RELEASES_FOR_PRODUCT 102 | if productId not in _RELEASES_FOR_PRODUCT: 103 | _RELEASES_FOR_PRODUCT[productId] = soapRequest( 104 | SOAP_GET_RELEASES_FOR_PRODUCT, 105 | productId=productId, 106 | sid=SID) 107 | return _RELEASES_FOR_PRODUCT[productId] 108 | 109 | _RELEASE_VARIANTS = {} 110 | def getReleaseVariants(releaseId): 111 | global _RELEASE_VARIANTS 112 | if releaseId not in _RELEASE_VARIANTS: 113 | _RELEASE_VARIANTS[releaseId] = soapRequest( 114 | SOAP_GET_RELEASE_VARIANTS, 115 | releaseId=releaseId, 116 | sid=SID) 117 | return _RELEASE_VARIANTS[releaseId] 118 | 119 | 120 | class Cli(cmd.Cmd): 121 | prompt = "(nfwx) " 122 | 123 | def do_EOF(self, arg): 124 | """When end-of-file is entered (Ctrl-D), the shell is exited.""" 125 | return True 126 | 127 | def do_sid(self, arg): 128 | """Print the session ID.""" 129 | print SID 130 | 131 | def do_products(self, arg): 132 | """List product-ids and their names.""" 133 | for item in getProductList(): 134 | if not arg or arg in item.marketName: 135 | print "%-20i %s" % (item.productID, item.marketName) 136 | 137 | def do_releases(self, arg): 138 | """List release-ids and versions for a given product-id.""" 139 | try: 140 | arg = int(arg, 10) 141 | except ValueError: 142 | import sys 143 | print >> sys.stderr, "Product id '%s' is not an integer" % arg 144 | 145 | for item in getReleasesForProduct(arg): 146 | print "%-20i %s" % (item.releaseID, item.version) 147 | 148 | def do_variants(self, arg): 149 | """List variant-ids and their names for a given release-id.""" 150 | try: 151 | arg = int(arg, 10) 152 | except ValueError: 153 | import sys 154 | print >> sys.stderr, "Release id '%s' is not an integer" % arg 155 | 156 | for item in getReleaseVariants(arg): 157 | vid = "%i:%i" % (arg, item.variantID) 158 | print "%-20s %s (%i files)" % (vid, item.name, len(item.files)) 159 | 160 | def do_urls(self, arg): 161 | """List file URLs for a given release-id:variant-id.""" 162 | rid, vid = arg.split(":", 1) 163 | try: 164 | rid = int(rid, 10) 165 | except ValueError: 166 | import sys 167 | print >> sys.stderr, "Release id '%s' is not an integer" % rid 168 | try: 169 | vid = int(vid, 10) 170 | except ValueError: 171 | import sys 172 | print >> sys.stderr, "Variant id '%s' is not an integer" % vid 173 | 174 | for item in getReleaseVariants(rid): 175 | if item.variantID == vid: 176 | break 177 | 178 | if item.variantID != vid: 179 | import sys 180 | print >> sys.stderr, "No such variantID '%i'" % vid 181 | return 182 | 183 | for fileinfo in item.files: 184 | print fileinfo.downloadURL 185 | 186 | def do_help(self, arg): 187 | """Shows information about commands.""" 188 | return cmd.Cmd.do_help(self, arg) 189 | 190 | 191 | 192 | if __name__ == "__main__": 193 | import sys 194 | cli = Cli() 195 | if len(sys.argv) > 1: 196 | cli.onecmd(" ".join(sys.argv[1:])) 197 | else: 198 | cli.cmdloop() 199 | 200 | --------------------------------------------------------------------------------