package org.microg.networklocation.backends.cellapi;
import android.content.Context;
import android.util.Log;
import org.microg.networklocation.data.CellSpec;
import org.microg.networklocation.data.LocationSpec;
import org.microg.networklocation.helper.Networking;
import org.microg.networklocation.source.LocationSource;
import org.microg.networklocation.source.OnlineDataSource;
import org.microg.networklocation.MainService;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Collection;
public class CellAPI extends OnlineDataSource implements LocationSource<CellSpec> {
private static final String TAG = "nlp.CellAPI";
private static final String NAME = "cell.vodafone.com";
private static final String DESCRIPTION = "Retrieve cell locations from vodafone.com when online";
private static final String COPYRIGHT = "© 2007-2014";
private static final String SERVICE_URL = "https://cellapi.vodafone.com/loc";
private static final String rid = "nogapps";
private static final String secret = "ohY7rahb";
private final Context context;
static final private java.util.Random random = new java.util.Random();
public CellAPI(Context context) {
super(context);
this.context = context;
}
@Override
public boolean isSourceAvailable() {
return true;
}
@Override
public String getCopyright() {
return COPYRIGHT;
}
@Override
public String getDescription() {
return DESCRIPTION;
}
@Override
public String getName() {
return NAME;
}
@Override
public Collection<LocationSpec<CellSpec>> retrieveLocation(Collection<CellSpec> cellSpecs) {
Collection<LocationSpec<CellSpec>> locationSpecs = new ArrayList<LocationSpec<CellSpec>>();
for (CellSpec spec : cellSpecs) {
try {
if (MainService.DEBUG) Log.d(TAG, "retrieveLocation: checking for " + spec);
java.util.Map<String,String> map = resolve(
Integer.toString(spec.getMcc()),
Integer.toString(spec.getMnc()),
Integer.toString(spec.getLac()),
Integer.toString(0),
Integer.toString(spec.getCid()),
"-");
int rcd = Integer.parseInt(map.get("rcd"));
if (rcd < 2030) { // 2030: based on mcc
final double lat = Double.parseDouble(map.get("lat"));
final double lon = Double.parseDouble(map.get("lon"));
double rad;
final double altitude = 0.0;
if (rcd == 2000) // rad included
rad = Double.parseDouble(map.get("rad"));
else
rad = 5000.0;
locationSpecs.add(new LocationSpec<CellSpec>(spec,
lat,
lon,
altitude,
rad
));
}
else {
Log.e(TAG, "retrieveLocation: error=" + rcd);
}
}
catch (Exception e) {
Log.e(TAG, "retrieveLocation: exception=" + e);
if (MainService.DEBUG) Log.wtf(TAG, "retrieveLocation: exception=" + e, e);
}
}
if (MainService.DEBUG) Log.d(TAG, "retrieveLocation: locationSpecs=" + locationSpecs);
return locationSpecs;
}
static String generateMD5(String input) throws Exception {
java.security.MessageDigest digest = java.security.MessageDigest.getInstance("md5");
return new java.math.BigInteger(1, digest.digest( input.getBytes("utf-8"))).toString(16).toLowerCase();
}
static java.util.Map<String,String> decode(String line) throws Exception {
java.util.StringTokenizer pairs = new java.util.StringTokenizer(line.trim(), "&");
java.util.Map<String,String> tx = new java.util.HashMap();
while (pairs.hasMoreTokens()) {
String pair = (String)pairs.nextToken();
if (pair.length() > 0) {
int index = pair.indexOf('=');
if (index > 0) {
String name = java.net.URLDecoder.decode(
pair.substring(0, index), "UTF-8");
String value = java.net.URLDecoder.decode(
pair.substring(index+1), "UTF-8");
tx.put(name, value);
}
}
}
return tx;
}
static String encode(java.util.Map<String,String> map) throws Exception {
StringBuffer res = new StringBuffer();
for (String key : map.keySet()) {
String value = map.get(key);
if (value != null)
if (res.length() > 0)
res.append('&');
res
.append(key)
.append('=')
.append(java.net.URLEncoder.encode(value, "utf-8"));
}
return res.toString();
}
static java.util.Map<String,String> resolve(
String mc,
String mn,
String la,
String ri,
String ci,
String uid
) throws Exception
{
String tim = Long.toString(System.currentTimeMillis() / 1000);
String ver = "1";
String correlation_id = null;
// enable if under log4j: correlation_id = org.apache.log4j.MDC.get("correlation-id");
if (correlation_id == null)
correlation_id = Long.toString(random.nextLong());
String aup = generateMD5(
secret +
// manually sorted:
ci +
la +
mc +
mn +
ri +
rid +
tim +
uid +
ver +
"");
// create the parameter block:
java.util.Map<String,String> map = new java.util.HashMap<String,String>();
map.put("mc", mc);
map.put("mn", mn);
map.put("ri", ri);
map.put("la", la);
map.put("ci", ci);
if (MainService.DEBUG) Log.d(TAG, "resolve: parameter=" + map);
java.net.URLConnection conn = new java.net.URL(SERVICE_URL + "?" + encode(map)).openConnection();
// fill in the meta parameter:
conn.setRequestProperty("x-vf-csl-aup", aup);
conn.setRequestProperty("x-vf-csl-rid", rid);
conn.setRequestProperty("x-vf-csl-tim", tim);
conn.setRequestProperty("x-vf-csl-uid", uid);
conn.setRequestProperty("x-vf-csl-ver", ver);
conn.setRequestProperty("x-correlation-id", correlation_id);
if (MainService.DEBUG) Log.d(TAG, "resolve: meta=" + conn.getRequestProperties());
java.io.InputStream input = conn.getInputStream();
byte[] buffer = new byte[1024];
String response = "";
int amount = 0;
while (amount != -1) {
amount = input.read(buffer);
if (amount > 0)
response += new String(buffer, 0, amount);
}
java.util.Map<String,String> ret = decode(response);
if (MainService.DEBUG) Log.d(TAG, "resolve: response=" + ret);
return ret;
}
}