| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2008, Google Inc. |
| 2 // |
| 3 // Redistribution and use in source and binary forms, with or without |
| 4 // modification, are permitted provided that the following conditions are met: |
| 5 // |
| 6 // 1. Redistributions of source code must retain the above copyright notice, |
| 7 // this list of conditions and the following disclaimer. |
| 8 // 2. Redistributions in binary form must reproduce the above copyright notice, |
| 9 // this list of conditions and the following disclaimer in the documentation |
| 10 // and/or other materials provided with the distribution. |
| 11 // 3. Neither the name of Google Inc. nor the names of its contributors may be |
| 12 // used to endorse or promote products derived from this software without |
| 13 // specific prior written permission. |
| 14 // |
| 15 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| 16 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| 17 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
| 18 // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 19 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| 20 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
| 21 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| 22 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| 23 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
| 24 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 25 |
| 26 // TODO(joth): port to chromium |
| 27 #if 0 |
| 28 |
| 29 #include "gears/geolocation/network_location_request.h" |
| 30 |
| 31 #include "gears/blob/blob_utils.h" |
| 32 #include "gears/blob/buffer_blob.h" |
| 33 #include "gears/localserver/common/http_constants.h" |
| 34 #include "third_party/jsoncpp/reader.h" |
| 35 #include "third_party/jsoncpp/value.h" |
| 36 #include "third_party/jsoncpp/writer.h" |
| 37 |
| 38 static const char *kGearsNetworkLocationProtocolVersion = "1.1.0"; |
| 39 |
| 40 static const char *kAccessTokenString = "access_token"; |
| 41 static const char *kLatitudeString = "latitude"; |
| 42 static const char *kLongitudeString = "longitude"; |
| 43 static const char *kAltitudeString = "altitude"; |
| 44 static const char *kAccuracyString = "accuracy"; |
| 45 static const char *kAltitudeAccuracyString = "altitude_accuracy"; |
| 46 // Note that the corresponding JavaScript Position property is 'gearsAddress'. |
| 47 static const char *kAddressString = "address"; |
| 48 static const char *kStreetNumberString = "street_number"; |
| 49 static const char *kStreetString = "street"; |
| 50 static const char *kPremisesString = "premises"; |
| 51 static const char *kCityString = "city"; |
| 52 static const char *kCountyString = "county"; |
| 53 static const char *kRegionString = "region"; |
| 54 static const char *kCountryString = "country"; |
| 55 static const char *kCountryCodeString = "country_code"; |
| 56 static const char *kPostalCodeString = "postal_code"; |
| 57 |
| 58 // Local functions |
| 59 static const char16* RadioTypeToString(RadioType type); |
| 60 // Adds a string if it's valid to the JSON object. |
| 61 static void AddString(const std::string &property_name, |
| 62 const std::string16 &value, |
| 63 Json::Value *object); |
| 64 // Adds an integer if it's valid to the JSON object. |
| 65 static void AddInteger(const std::string &property_name, |
| 66 const int &value, |
| 67 Json::Value *object); |
| 68 // Returns true if the value is a valid angle. |
| 69 static bool IsValidAngle(const double &value); |
| 70 // Parses the server response body. Returns true if parsing was successful. |
| 71 static bool ParseServerResponse(const std::string &response_body, |
| 72 int64 timestamp, |
| 73 bool is_reverse_geocode, |
| 74 Position *position, |
| 75 std::string16 *access_token); |
| 76 static void AddRadioData(const RadioData &radio_data, Json::Value *body_object); |
| 77 static void AddWifiData(const WifiData &wifi_data, Json::Value *body_object); |
| 78 |
| 79 // static |
| 80 NetworkLocationRequest *NetworkLocationRequest::Create( |
| 81 BrowsingContext *browsing_context, |
| 82 const std::string16 &url, |
| 83 const std::string16 &host_name, |
| 84 ListenerInterface *listener) { |
| 85 scoped_ptr<NetworkLocationRequest> request( |
| 86 new NetworkLocationRequest(browsing_context, url, host_name, listener)); |
| 87 assert(request.get()); |
| 88 if (!request.get() || !request->Init() || !request->Start()) { |
| 89 return NULL; |
| 90 } |
| 91 return request.release(); |
| 92 } |
| 93 |
| 94 NetworkLocationRequest::NetworkLocationRequest( |
| 95 BrowsingContext *browsing_context, |
| 96 const std::string16 &url, |
| 97 const std::string16 &host_name, |
| 98 ListenerInterface *listener) |
| 99 : AsyncTask(browsing_context), |
| 100 listener_(listener), |
| 101 url_(url), |
| 102 host_name_(host_name), |
| 103 is_shutting_down_(false) { |
| 104 } |
| 105 |
| 106 bool NetworkLocationRequest::MakeRequest(const std::string16 &access_token, |
| 107 const RadioData &radio_data, |
| 108 const WifiData &wifi_data, |
| 109 bool request_address, |
| 110 const std::string16 &address_language, |
| 111 double latitude, |
| 112 double longitude, |
| 113 int64 timestamp) { |
| 114 is_reverse_geocode_ = request_address && |
| 115 IsValidAngle(latitude) && |
| 116 IsValidAngle(longitude); |
| 117 if (!FormRequestBody(host_name_, access_token, radio_data, wifi_data, |
| 118 request_address, address_language, latitude, longitude, |
| 119 is_reverse_geocode_, &post_body_)) { |
| 120 return false; |
| 121 } |
| 122 timestamp_ = timestamp; |
| 123 |
| 124 thread_event_.Signal(); |
| 125 return true; |
| 126 } |
| 127 |
| 128 // AsyncTask implementation. |
| 129 void NetworkLocationRequest::Run() { |
| 130 while (true) { |
| 131 thread_event_.Wait(); |
| 132 if (is_shutting_down_) { |
| 133 break; |
| 134 } |
| 135 MakeRequestImpl(); |
| 136 } |
| 137 } |
| 138 |
| 139 void NetworkLocationRequest::MakeRequestImpl() { |
| 140 WebCacheDB::PayloadInfo payload; |
| 141 // TODO(andreip): remove this once WebCacheDB::PayloadInfo.data is a Blob. |
| 142 scoped_refptr<BlobInterface> payload_data; |
| 143 bool result = HttpPost(url_.c_str(), |
| 144 false, // Not capturing, so follow redirects |
| 145 NULL, // reason_header_value |
| 146 HttpConstants::kMimeApplicationJson, // Content-Type |
| 147 NULL, // mod_since_date |
| 148 NULL, // required_cookie |
| 149 true, // disable_browser_cookies |
| 150 post_body_.get(), |
| 151 &payload, |
| 152 &payload_data, |
| 153 NULL, // was_redirected |
| 154 NULL, // full_redirect_url |
| 155 NULL); // error_message |
| 156 |
| 157 MutexLock lock(&is_processing_response_mutex_); |
| 158 // is_aborted_ may be true even if HttpPost succeeded. |
| 159 if (is_aborted_) { |
| 160 LOG(("NetworkLocationRequest::Run() : HttpPost request was cancelled.\n")); |
| 161 return; |
| 162 } |
| 163 |
| 164 if (listener_) { |
| 165 Position position; |
| 166 std::string response_body; |
| 167 if (result) { |
| 168 // If HttpPost succeeded, payload_data is guaranteed to be non-NULL. |
| 169 assert(payload_data.get()); |
| 170 if (!payload_data->Length() || |
| 171 !BlobToString(payload_data.get(), &response_body)) { |
| 172 LOG(("NetworkLocationRequest::Run() : Failed to get response body.\n")); |
| 173 } |
| 174 } |
| 175 std::string16 access_token; |
| 176 GetLocationFromResponse(result, payload.status_code, response_body, |
| 177 timestamp_, url_, is_reverse_geocode_, |
| 178 &position, &access_token); |
| 179 |
| 180 LOG(("NetworkLocationRequest::Run() : Calling listener with position.\n")); |
| 181 bool server_error = |
| 182 !result || (payload.status_code >= 500 && payload.status_code < 600); |
| 183 listener_->LocationResponseAvailable(position, server_error, access_token); |
| 184 } |
| 185 } |
| 186 |
| 187 // static |
| 188 bool NetworkLocationRequest::FormRequestBody( |
| 189 const std::string16 &host_name, |
| 190 const std::string16 &access_token, |
| 191 const RadioData &radio_data, |
| 192 const WifiData &wifi_data, |
| 193 bool request_address, |
| 194 std::string16 address_language, |
| 195 double latitude, |
| 196 double longitude, |
| 197 bool is_reverse_geocode, |
| 198 scoped_refptr<BlobInterface> *blob) { |
| 199 assert(blob); |
| 200 Json::Value body_object; |
| 201 assert(body_object.isObject()); |
| 202 // Version and host are required. |
| 203 if (host_name.empty()) { |
| 204 return false; |
| 205 } |
| 206 body_object["version"] = Json::Value(kGearsNetworkLocationProtocolVersion); |
| 207 AddString("host", host_name, &body_object); |
| 208 |
| 209 AddString("access_token", access_token, &body_object); |
| 210 |
| 211 body_object["request_address"] = request_address; |
| 212 AddString("address_language", address_language, &body_object); |
| 213 |
| 214 if (is_reverse_geocode) { |
| 215 assert(request_address); |
| 216 assert(IsValidAngle(latitude) && IsValidAngle(longitude)); |
| 217 Json::Value location; |
| 218 location["latitude"] = Json::Value(latitude); |
| 219 location["longitude"] = Json::Value(longitude); |
| 220 body_object["location"] = location; |
| 221 } else { |
| 222 AddRadioData(radio_data, &body_object); |
| 223 AddWifiData(wifi_data, &body_object); |
| 224 } |
| 225 |
| 226 Json::FastWriter writer; |
| 227 // We always use the platform independent 'C' locale when writing the JSON |
| 228 // request, irrespective of the browser's locale. This avoids the need for |
| 229 // the network location provider to determine the locale of the request and |
| 230 // parse the JSON accordingly. |
| 231 #ifdef OS_WINCE |
| 232 // WinCE does not support setlocale. |
| 233 #else |
| 234 char *current_locale = setlocale(LC_NUMERIC, "C"); |
| 235 #endif |
| 236 std::string body_string = writer.write(body_object); |
| 237 #ifdef OS_WINCE |
| 238 // WinCE does not support setlocale. |
| 239 #else |
| 240 setlocale(LC_NUMERIC, current_locale); |
| 241 #endif |
| 242 LOG(("NetworkLocationRequest::FormRequestBody(): Formed body %s.\n", |
| 243 body_string.c_str())); |
| 244 |
| 245 blob->reset(new BufferBlob(body_string.c_str(), body_string.size())); |
| 246 return true; |
| 247 } |
| 248 |
| 249 // static |
| 250 void NetworkLocationRequest::GetLocationFromResponse( |
| 251 bool http_post_result, |
| 252 int status_code, |
| 253 const std::string &response_body, |
| 254 int64 timestamp, |
| 255 const std::string16 &server_url, |
| 256 bool is_reverse_geocode, |
| 257 Position *position, |
| 258 std::string16 *access_token) { |
| 259 assert(position); |
| 260 assert(access_token); |
| 261 |
| 262 // HttpPost can fail for a number of reasons. Most likely this is because |
| 263 // we're offline, or there was no response. |
| 264 if (!http_post_result) { |
| 265 LOG(("NetworkLocationRequest::GetLocationFromResponse() : HttpPost request " |
| 266 "failed.\n")); |
| 267 position->error_code = Position::ERROR_CODE_POSITION_UNAVAILABLE; |
| 268 position->error_message = STRING16(L"No response from network provider " |
| 269 L"at "); |
| 270 position->error_message += server_url.c_str(); |
| 271 position->error_message += STRING16(L"."); |
| 272 } else if (status_code == HttpConstants::HTTP_OK) { |
| 273 // We use the timestamp from the device data that was used to generate |
| 274 // this position fix. |
| 275 if (ParseServerResponse(response_body, timestamp, is_reverse_geocode, |
| 276 position, access_token)) { |
| 277 // The response was successfully parsed, but it may not be a valid |
| 278 // position fix. |
| 279 if (!position->IsGoodFix()) { |
| 280 position->error_code = Position::ERROR_CODE_POSITION_UNAVAILABLE; |
| 281 position->error_message = STRING16(L"Network provider at "); |
| 282 position->error_message += server_url.c_str(); |
| 283 position->error_message += STRING16(L" did not provide a good position " |
| 284 L"fix."); |
| 285 } |
| 286 } else { |
| 287 // We failed to parse the repsonse. |
| 288 LOG(("NetworkLocationRequest::GetLocationFromResponse() : Response " |
| 289 "malformed.\n")); |
| 290 position->error_code = Position::ERROR_CODE_POSITION_UNAVAILABLE; |
| 291 position->error_message = STRING16(L"Response from network provider at "); |
| 292 position->error_message += server_url.c_str(); |
| 293 position->error_message += STRING16(L" was malformed."); |
| 294 } |
| 295 } else { |
| 296 // The response was bad. |
| 297 LOG(("NetworkLocationRequest::GetLocationFromResponse() : HttpPost " |
| 298 "response was bad.\n")); |
| 299 position->error_code = Position::ERROR_CODE_POSITION_UNAVAILABLE; |
| 300 position->error_message = STRING16(L"Network provider at "); |
| 301 position->error_message += server_url.c_str(); |
| 302 position->error_message += STRING16(L" returned error code "); |
| 303 position->error_message += IntegerToString16(status_code); |
| 304 position->error_message += STRING16(L"."); |
| 305 } |
| 306 } |
| 307 |
| 308 void NetworkLocationRequest::StopThreadAndDelete() { |
| 309 // The FF implementation of AsyncTask::Abort() delivers a message to the UI |
| 310 // thread to cancel the request. So if we call this method on the UI thread, |
| 311 // we must return to the OS before the call to Abort() will take effect. In |
| 312 // particular, we can't call Abort() then block here waiting for HttpPost to |
| 313 // return. |
| 314 is_shutting_down_ = true; |
| 315 thread_event_.Signal(); |
| 316 is_processing_response_mutex_.Lock(); |
| 317 Abort(); |
| 318 is_processing_response_mutex_.Unlock(); |
| 319 DeleteWhenDone(); |
| 320 } |
| 321 |
| 322 // Local functions. |
| 323 |
| 324 static const char16* RadioTypeToString(RadioType type) { |
| 325 switch (type) { |
| 326 case RADIO_TYPE_UNKNOWN: |
| 327 return STRING16(L"unknown"); |
| 328 case RADIO_TYPE_GSM: |
| 329 return STRING16(L"gsm"); |
| 330 case RADIO_TYPE_CDMA: |
| 331 return STRING16(L"cdma"); |
| 332 case RADIO_TYPE_WCDMA: |
| 333 return STRING16(L"wcdma"); |
| 334 default: |
| 335 assert(false); |
| 336 } |
| 337 return NULL; |
| 338 } |
| 339 |
| 340 static void AddString(const std::string &property_name, |
| 341 const std::string16 &value, |
| 342 Json::Value *object) { |
| 343 assert(object); |
| 344 assert(object->isObject()); |
| 345 if (!value.empty()) { |
| 346 std::string value_utf8; |
| 347 if (String16ToUTF8(value.c_str(), value.size(), &value_utf8)) { |
| 348 (*object)[property_name] = Json::Value(value_utf8); |
| 349 } |
| 350 } |
| 351 } |
| 352 |
| 353 static void AddInteger(const std::string &property_name, |
| 354 const int &value, |
| 355 Json::Value *object) { |
| 356 assert(object); |
| 357 assert(object->isObject()); |
| 358 if (kint32min != value) { |
| 359 (*object)[property_name] = Json::Value(value); |
| 360 } |
| 361 } |
| 362 |
| 363 static bool IsValidAngle(const double &value) { |
| 364 return value >= -180.0 && value <= 180.0; |
| 365 } |
| 366 |
| 367 // Numeric values without a decimal point have type integer and IsDouble() will |
| 368 // return false. This is convenience function for detecting integer or floating |
| 369 // point numeric values. Note that isIntegral() includes boolean values, which |
| 370 // is not what we want. |
| 371 static bool IsDoubleOrInt(const Json::Value &object, |
| 372 const std::string &property_name) { |
| 373 return object[property_name].isDouble() || object[property_name].isInt(); |
| 374 } |
| 375 |
| 376 // The JsValue::asXXX() methods return zero if a property isn't specified. For |
| 377 // our purposes, zero is a valid value, so we have to test for existence. |
| 378 |
| 379 // Gets a double if it's present. |
| 380 static bool GetAsDouble(const Json::Value &object, |
| 381 const std::string &property_name, |
| 382 double *out) { |
| 383 assert(out); |
| 384 if (!IsDoubleOrInt(object, property_name)) { |
| 385 return false; |
| 386 } |
| 387 *out = object[property_name].asDouble(); |
| 388 return true; |
| 389 } |
| 390 |
| 391 // Gets a string if it's present. |
| 392 static bool GetAsString(const Json::Value &object, |
| 393 const std::string &property_name, |
| 394 std::string16 *out) { |
| 395 assert(out); |
| 396 if (!object[property_name].isString()) { |
| 397 return false; |
| 398 } |
| 399 std::string out_utf8 = object[property_name].asString(); |
| 400 return UTF8ToString16(out_utf8.c_str(), out_utf8.size(), out); |
| 401 } |
| 402 |
| 403 static bool ParseServerResponse(const std::string &response_body, |
| 404 int64 timestamp, |
| 405 bool is_reverse_geocode, |
| 406 Position *position, |
| 407 std::string16 *access_token) { |
| 408 assert(position); |
| 409 assert(access_token); |
| 410 |
| 411 if (response_body.empty()) { |
| 412 LOG(("ParseServerResponse() : Response was empty.\n")); |
| 413 return false; |
| 414 } |
| 415 LOG(("ParseServerResponse() : Parsing response %s.\n", |
| 416 response_body.c_str())); |
| 417 |
| 418 // Parse the response, ignoring comments. The JSON reposne from the network |
| 419 // location provider should always use the 'C' locale. |
| 420 Json::Reader reader; |
| 421 Json::Value response_object; |
| 422 #ifdef OS_WINCE |
| 423 // WinCE does not support setlocale. |
| 424 #else |
| 425 char *current_locale = setlocale(LC_NUMERIC, "C"); |
| 426 #endif |
| 427 bool res = reader.parse(response_body, response_object, false); |
| 428 #ifdef OS_WINCE |
| 429 // WinCE does not support setlocale. |
| 430 #else |
| 431 setlocale(LC_NUMERIC, current_locale); |
| 432 #endif |
| 433 if (!res) { |
| 434 LOG(("ParseServerResponse() : Failed to parse response : %s.\n", |
| 435 reader.getFormatedErrorMessages().c_str())); |
| 436 return false; |
| 437 } |
| 438 |
| 439 if (!response_object.isObject()) { |
| 440 LOG(("ParseServerResponse() : Unexpected response type: %d.\n", |
| 441 response_object.type())); |
| 442 return false; |
| 443 } |
| 444 |
| 445 // Get the access token. |
| 446 GetAsString(response_object, kAccessTokenString, access_token); |
| 447 |
| 448 // Get the location |
| 449 Json::Value location = response_object["location"]; |
| 450 |
| 451 // If the network provider was unable to provide a position fix, it should |
| 452 // return a 200 with location == null. |
| 453 if (location.type() == Json::nullValue) { |
| 454 LOG(("ParseServerResponse() : Location is null.\n")); |
| 455 return true; |
| 456 } |
| 457 |
| 458 // If location is not null, it must be an object. |
| 459 if (!location.isObject()) { |
| 460 return false; |
| 461 } |
| 462 |
| 463 // latitude and longitude fields are always required. |
| 464 if (!GetAsDouble(location, kLatitudeString, &position->latitude) || |
| 465 !GetAsDouble(location, kLongitudeString, &position->longitude)) { |
| 466 return false; |
| 467 } |
| 468 |
| 469 // If it's not a reverse geocode request, the accuracy field is also required. |
| 470 if (is_reverse_geocode) { |
| 471 position->accuracy = 0.0; |
| 472 } else { |
| 473 if (!GetAsDouble(location, kAccuracyString, &position->accuracy)) { |
| 474 return false; |
| 475 } |
| 476 } |
| 477 |
| 478 // Other fields are optional. |
| 479 GetAsDouble(location, kAltitudeString, &position->altitude); |
| 480 GetAsDouble(location, kAltitudeAccuracyString, &position->altitude_accuracy); |
| 481 Json::Value address = location[kAddressString]; |
| 482 if (address.isObject()) { |
| 483 GetAsString(address, kStreetNumberString, &position->address.street_number); |
| 484 GetAsString(address, kStreetString, &position->address.street); |
| 485 GetAsString(address, kPremisesString, &position->address.premises); |
| 486 GetAsString(address, kCityString, &position->address.city); |
| 487 GetAsString(address, kCountyString, &position->address.county); |
| 488 GetAsString(address, kRegionString, &position->address.region); |
| 489 GetAsString(address, kCountryString, &position->address.country); |
| 490 GetAsString(address, kCountryCodeString, &position->address.country_code); |
| 491 GetAsString(address, kPostalCodeString, &position->address.postal_code); |
| 492 } |
| 493 |
| 494 position->timestamp = timestamp; |
| 495 return true; |
| 496 } |
| 497 |
| 498 static void AddRadioData(const RadioData &radio_data, |
| 499 Json::Value *body_object) { |
| 500 assert(body_object); |
| 501 |
| 502 AddInteger("home_mobile_country_code", radio_data.home_mobile_country_code, |
| 503 body_object); |
| 504 AddInteger("home_mobile_network_code", radio_data.home_mobile_network_code, |
| 505 body_object); |
| 506 AddString("radio_type", RadioTypeToString(radio_data.radio_type), |
| 507 body_object); |
| 508 AddString("carrier", radio_data.carrier, body_object); |
| 509 |
| 510 Json::Value cell_towers; |
| 511 assert(cell_towers.isArray()); |
| 512 int num_cell_towers = static_cast<int>(radio_data.cell_data.size()); |
| 513 for (int i = 0; i < num_cell_towers; ++i) { |
| 514 Json::Value cell_tower; |
| 515 assert(cell_tower.isObject()); |
| 516 AddInteger("cell_id", radio_data.cell_data[i].cell_id, &cell_tower); |
| 517 AddInteger("location_area_code", radio_data.cell_data[i].location_area_code, |
| 518 &cell_tower); |
| 519 AddInteger("mobile_country_code", |
| 520 radio_data.cell_data[i].mobile_country_code, &cell_tower); |
| 521 AddInteger("mobile_network_code", |
| 522 radio_data.cell_data[i].mobile_network_code, &cell_tower); |
| 523 AddInteger("age", radio_data.cell_data[i].age, &cell_tower); |
| 524 AddInteger("signal_strength", radio_data.cell_data[i].radio_signal_strength, |
| 525 &cell_tower); |
| 526 AddInteger("timing_advance", radio_data.cell_data[i].timing_advance, |
| 527 &cell_tower); |
| 528 cell_towers[i] = cell_tower; |
| 529 } |
| 530 if (num_cell_towers > 0) { |
| 531 (*body_object)["cell_towers"] = cell_towers; |
| 532 } |
| 533 } |
| 534 |
| 535 static void AddWifiData(const WifiData &wifi_data, Json::Value *body_object) { |
| 536 assert(body_object); |
| 537 |
| 538 if (wifi_data.access_point_data.empty()) { |
| 539 return; |
| 540 } |
| 541 |
| 542 Json::Value wifi_towers; |
| 543 assert(wifi_towers.isArray()); |
| 544 for (WifiData::AccessPointDataSet::const_iterator iter = |
| 545 wifi_data.access_point_data.begin(); |
| 546 iter != wifi_data.access_point_data.end(); |
| 547 iter++) { |
| 548 Json::Value wifi_tower; |
| 549 assert(wifi_tower.isObject()); |
| 550 AddString("mac_address", iter->mac_address, &wifi_tower); |
| 551 AddInteger("signal_strength", iter->radio_signal_strength, &wifi_tower); |
| 552 AddInteger("age", iter->age, &wifi_tower); |
| 553 AddInteger("channel", iter->channel, &wifi_tower); |
| 554 AddInteger("signal_to_noise", iter->signal_to_noise, &wifi_tower); |
| 555 AddString("ssid", iter->ssid, &wifi_tower); |
| 556 wifi_towers.append(wifi_tower); |
| 557 } |
| 558 (*body_object)["wifi_towers"] = wifi_towers; |
| 559 } |
| 560 |
| 561 #endif // if 0 |
| OLD | NEW |