/**
   * Synchroniseert verwijderde polygonen met de server
   *
   * @param group groupid om polygonen uit te syncen
   * @throws SyncException
   */
  private void deletePolygons(int group) throws SyncException {
    Cursor c = db.getRemovedPolygons(group);
    int polygonid = 0;

    if (!c.moveToFirst()) {
      return; // Niks te syncen, dus gelijk klaar!
    }

    do {
      polygonid = c.getInt(0);

      HttpDelete httpd = new HttpDelete(serverUrl + "polygon/id/" + polygonid);
      UsernamePasswordCredentials creds = new UsernamePasswordCredentials(mappUser, mappPass);

      try {
        httpd.addHeader(new BasicScheme().authenticate(creds, httpd));
      } catch (AuthenticationException e1) {
        Log.e(Mapp.TAG, e1.getStackTrace().toString());
        throw new SyncException("Authentication failed");
      }

      HttpResponse response;

      try {
        response = httpclient.execute(httpd);

        if (response.getStatusLine().getStatusCode() == 418) {
          throw new SyncException("Unable to synchronize because the server is a teapot.");
        } else if (response.getStatusLine().getStatusCode() == 401) {
          throw new SyncException("Not authorized");
        } else if (response.getStatusLine().getStatusCode() != 200) {
          // Er is iets mis gegaan.
          // Lees de uitvoer
          InputStream is = response.getEntity().getContent();
          BufferedReader r = new BufferedReader(new InputStreamReader(is));
          StringBuilder total = new StringBuilder();
          String line;
          while ((line = r.readLine()) != null) {
            total.append(line);
          }

          JSONObject result = null;
          result = new JSONObject(total.toString());
          Log.e(Mapp.TAG, "Sync error: " + result.getString("message"));
          throw new SyncException(result.getString("message"));
        } else {
          db.removeRemovedPolygon(polygonid);
        }
      } catch (ClientProtocolException e) {
        Log.e(Mapp.TAG, e.getMessage());
        throw new SyncException("Epic HTTP failure");
      } catch (IOException e) {
        Log.e(Mapp.TAG, e.getMessage());
        throw new SyncException("Exception during server synchronisation");
      } catch (JSONException e) {
        Log.e(Mapp.TAG, "Sync failed. Getting status message from JSON response failed.");
        throw new SyncException("Invalid server response");
      }
    } while (c.moveToNext());
  }
  /**
   * Geeft de huidige servertijd terug
   *
   * @return de huidige servertijd als unix-timestamp
   * @throws SyncException
   */
  private int getSyncTimeStamp() throws SyncException {
    HttpGet httpg = new HttpGet(serverUrl + "time/");
    UsernamePasswordCredentials creds = new UsernamePasswordCredentials(mappUser, mappPass);

    try {
      httpg.addHeader(new BasicScheme().authenticate(creds, httpg));
    } catch (AuthenticationException e1) {
      Log.e(Mapp.TAG, e1.getMessage());
      throw new SyncException("Authentication failed");
    }

    HttpResponse response;

    try {
      response = httpclient.execute(httpg);

      // Lees het resultaat van de actie in
      InputStream is = response.getEntity().getContent();
      BufferedReader r = new BufferedReader(new InputStreamReader(is));
      StringBuilder total = new StringBuilder();
      String line;
      while ((line = r.readLine()) != null) {
        total.append(line);
      }

      if (response.getStatusLine().getStatusCode() == 418) {
        throw new SyncException("Unable to synchronize because the server is a teapot.");
      } else if (response.getStatusLine().getStatusCode() != 200) {
        // Er is iets mis gegaan.
        JSONObject result = new JSONObject(total.toString());
        Log.e(Mapp.TAG, "Sync error: " + result.getString("message"));
        throw new SyncException(result.getString("message"));
      } else {
        // Alles is blijkbaar goed gegaan
        JSONObject result = new JSONObject(total.toString());
        return result.getInt("current_time");
      }
    } catch (ClientProtocolException e) {
      Log.e(Mapp.TAG, e.getMessage());
      throw new SyncException("Epic HTTP failure");
    } catch (IOException e) {
      Log.e(Mapp.TAG, e.getMessage());
      throw new SyncException("Exception during server synchronisation");
    } catch (JSONException e) {
      Log.e(Mapp.TAG, "Sync failed. Response is no valid JSON or expected variable not found.");
      throw new SyncException("Invalid server response");
    }
  }
  public static boolean sendTasksHistory(Cursor c) throws NetworkErrorException {

    if (c.getCount() == 0) return false;
    JSONArray unsyncedHistory = new JSONArray();
    StringEntity entity = null;
    JSONArray entry;

    while (c.moveToNext()) {
      try {
        entry = new JSONArray();
        entry.put(c.getInt(c.getColumnIndex(DataStorage.C_TASK_REFERENCE)));
        entry.put(c.getInt(c.getColumnIndex(DataStorage.C_TASK_STATE_CHANGED_TO)));
        entry.put(c.getLong(c.getColumnIndex(DataStorage.C_CHANGE_TIME)));
        entry.put(c.getString(c.getColumnIndex(DataStorage.C_CHANGE_DESCRIPTION)));
        entry.put(c.getDouble(c.getColumnIndex(DataStorage.C_CHANGE_LATITUDE)));
        entry.put(c.getDouble(c.getColumnIndex(DataStorage.C_CHANGE_LONGITUDE)));
        unsyncedHistory.put(entry);
      } catch (JSONException e) {
        e.printStackTrace();
      }
    }
    c.close();
    try {
      Log.d("JSON TIME FROM DATABASE start, finish", unsyncedHistory.toString());

      entity = new StringEntity(unsyncedHistory.toString(), "UTF-8");
    } catch (UnsupportedEncodingException e) {

    }
    try {
      HttpPost post = new HttpPost(HOST + "new_tasks_history/");
      post.setEntity(entity);
      post.addHeader("Accept", "application/json");
      post.addHeader("Content-type", "application/json");
      try {
        post.addHeader(new BasicScheme().authenticate(credentials, post));
      } catch (AuthenticationException e) {
        Log.d(TAG, e.getMessage());
      }
      apiCall(post);
    } catch (NullPointerException e) {
      throw new NetworkErrorException("404");
    }
    return true;
  }
 public static ArrayList<Task> getTasksSinceLastSync() throws NetworkErrorException {
   try {
     HttpGet get = new HttpGet(HOST + "get_tasks_since_last_sync/");
     Log.d(TAG, "request to: " + HOST);
     try {
       try {
         get.addHeader(new BasicScheme().authenticate(credentials, get));
       } catch (AuthenticationException e) {
         Log.d(TAG, e.getMessage() + "lalal");
       }
     } catch (IllegalArgumentException e) {
       throw new NetworkErrorException("401");
     }
     return buildTaskList(apiCall(get));
   } catch (NullPointerException e) {
     throw new NetworkErrorException("404");
   }
 }
  public static boolean changeTasksStates(Cursor c) throws NetworkErrorException {

    if (c.getCount() == 0)
      return false; // no need to reset nonsynced task states, there are none pending
    JSONArray pendingTasks = new JSONArray();
    StringEntity entity = null;
    JSONArray entry;

    while (c.moveToNext()) {
      entry = new JSONArray();
      entry.put(Long.toString(c.getLong(c.getColumnIndex(DataStorage.C_ID))));
      entry.put(c.getInt(c.getColumnIndex(DataStorage.C_STATE)));
      entry.put(c.getLong(c.getColumnIndex(DataStorage.C_START_TIME)));
      entry.put(c.getLong(c.getColumnIndex(DataStorage.C_FINISH_TIME)));
      pendingTasks.put(entry);
    }
    c.close();
    try {
      Log.d("JSON TIME FROM DATABASE start, finish", pendingTasks.toString());

      entity = new StringEntity(pendingTasks.toString(), "UTF-8");
    } catch (UnsupportedEncodingException e) {

    }
    try {
      HttpPost post = new HttpPost(HOST + "change_tasks_states/");
      post.setEntity(entity);
      post.addHeader("Accept", "application/json");
      post.addHeader("Content-type", "application/json");
      try {
        post.addHeader(new BasicScheme().authenticate(credentials, post));
      } catch (AuthenticationException e) {
        Log.d(TAG, e.getMessage());
      }
      apiCall(post);
    } catch (NullPointerException e) {
      throw new NetworkErrorException("404");
    }
    return true;
  }
  /**
   * Add a list of status messages to the contacts provider.
   *
   * @param context the context to use
   * @param accountName the username of the logged in user
   * @param statuses the list of statuses to store
   */
  @TargetApi(15)
  public static void insertStreamStatuses(Context context, String username) {
    final ContentValues values = new ContentValues();
    final ContentResolver resolver = context.getContentResolver();
    final BatchOperation batchOperation = new BatchOperation(context, resolver);
    List<Long> currentContacts = lookupAllContacts(resolver);

    for (long id : currentContacts) {

      String friendUsername = lookupUsername(resolver, id);
      long watermark = lookupHighWatermark(resolver, id);
      long newWatermark = watermark;

      try {
        List<Status> statuses = DeliciousFeed.fetchFriendStatuses(friendUsername);

        for (Status status : statuses) {

          if (status.getTimeStamp().getTime() > watermark) {

            if (status.getTimeStamp().getTime() > newWatermark)
              newWatermark = status.getTimeStamp().getTime();

            values.clear();
            values.put(StreamItems.RAW_CONTACT_ID, id);
            values.put(StreamItems.TEXT, status.getStatus());
            values.put(StreamItems.TIMESTAMP, status.getTimeStamp().getTime());
            values.put(StreamItems.ACCOUNT_NAME, username);
            values.put(StreamItems.ACCOUNT_TYPE, Constants.ACCOUNT_TYPE);
            values.put(StreamItems.RES_ICON, R.drawable.ic_main);
            values.put(StreamItems.RES_PACKAGE, context.getPackageName());
            values.put(StreamItems.RES_LABEL, R.string.label);

            batchOperation.add(
                ContactOperations.newInsertCpo(StreamItems.CONTENT_URI, false)
                    .withValues(values)
                    .build());
            // A sync adapter should batch operations on multiple contacts,
            // because it will make a dramatic performance difference.
            if (batchOperation.size() >= 50) {
              batchOperation.execute();
            }
          }
        }

        values.clear();
        values.put(RawContacts.SYNC1, Long.toString(newWatermark));
        batchOperation.add(
            ContactOperations.newUpdateCpo(RawContacts.CONTENT_URI, false)
                .withValues(values)
                .withSelection(RawContacts._ID + "=?", new String[] {Long.toString(id)})
                .build());

        batchOperation.execute();

      } catch (AuthenticationException e) {
        e.printStackTrace();
      } catch (JSONException e) {
        e.printStackTrace();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
  /**
   * Stuurt nieuwe lidmaatschappen naar 't servertje
   *
   * @throws SyncException
   */
  private void putMemberships() throws SyncException {
    Cursor c = db.getNewMemberships();
    String email = "";
    int id = 0;

    if (!c.moveToFirst()) {
      return; // Niks te syncen, dus gelijk klaar!
    }

    do {
      HttpPut httpp = new HttpPut(serverUrl + "membership");
      UsernamePasswordCredentials creds = new UsernamePasswordCredentials(mappUser, mappPass);

      id = c.getInt(0);
      email = c.getString(1);

      List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
      nameValuePairs.add(new BasicNameValuePair("email", email));
      nameValuePairs.add(new BasicNameValuePair("group_id", id + ""));

      try {
        httpp.addHeader(new BasicScheme().authenticate(creds, httpp));
        httpp.setEntity(new UrlEncodedFormEntity(nameValuePairs));
      } catch (AuthenticationException e1) {
        Log.e(Mapp.TAG, e1.getStackTrace().toString());
        throw new SyncException("Authentication failed");
      } catch (UnsupportedEncodingException e) {
        Log.e(Mapp.TAG, e.getStackTrace().toString());
        throw new SyncException("Failed to encode data");
      }

      HttpResponse response;

      try {
        response = httpclient.execute(httpp);

        // Lees het resultaat van de actie in
        JSONObject result = null;
        InputStream is = response.getEntity().getContent();
        BufferedReader r = new BufferedReader(new InputStreamReader(is));
        StringBuilder total = new StringBuilder();
        String line;
        while ((line = r.readLine()) != null) {
          total.append(line);
        }

        result = new JSONObject(total.toString());

        if (response.getStatusLine().getStatusCode() == 418) {
          throw new SyncException("Unable to synchronize because the server is a teapot.");
        } else if (response.getStatusLine().getStatusCode() == 401) {
          throw new SyncException("Not authorized");
        } else if (response.getStatusLine().getStatusCode() != 200) {
          // Er is iets mis gegaan.
          Log.e(Mapp.TAG, "Sync error: " + result.getString("message"));
          throw new SyncException(result.getString("message"));
        } else {
          // Het 'nieuw'-vlaggetje verwijderen
          db.setMembershipIsSynced(id, email);
        }
      } catch (ClientProtocolException e) {
        Log.e(Mapp.TAG, e.getMessage());
        throw new SyncException("Epic HTTP failure");
      } catch (IOException e) {
        Log.e(Mapp.TAG, e.getMessage());
        throw new SyncException("Exception during server synchronisation");
      } catch (JSONException e) {
        Log.e(Mapp.TAG, "Sync failed. Response is no valid JSON or expected variable not found.");
        throw new SyncException("Invalid server response");
      }
    } while (c.moveToNext());
  }
  /**
   * Haalt info over de gegeven groep op en slaat deze lokaal op
   *
   * @param i het id van de op te halen groep
   * @param update of het een update betreft of een nieuwe polygoon is
   * @throws SyncException
   */
  private void updateGroup(int id, boolean update) throws SyncException {
    HttpGet httpg = new HttpGet(serverUrl + "group/id/" + id);
    UsernamePasswordCredentials creds = new UsernamePasswordCredentials(mappUser, mappPass);

    try {
      httpg.addHeader(new BasicScheme().authenticate(creds, httpg));
    } catch (AuthenticationException e1) {
      Log.e(Mapp.TAG, e1.getMessage());
      throw new SyncException("Authentication failed");
    }

    HttpResponse response;

    try {
      response = httpclient.execute(httpg);

      // Lees het resultaat van de actie in
      InputStream is = response.getEntity().getContent();
      BufferedReader r = new BufferedReader(new InputStreamReader(is));
      StringBuilder total = new StringBuilder();
      String line;
      while ((line = r.readLine()) != null) {
        total.append(line);
      }

      if (response.getStatusLine().getStatusCode() == 418) {
        throw new SyncException("Unable to synchronize because the server is a teapot.");
      } else if (response.getStatusLine().getStatusCode() == 401) {
        throw new SyncException("Not authorized");
      } else if (response.getStatusLine().getStatusCode() != 200) {
        // Er is iets mis gegaan.
        JSONObject result = new JSONObject(total.toString());
        Log.e(Mapp.TAG, "Sync error: " + result.getString("message"));
        throw new SyncException(result.getString("message"));
      } else {
        // Alles is blijkbaar goed gegaan
        JSONObject result = new JSONObject(total.toString());

        if (!update) {
          db.addGroupFromServer(id, result.optString("email"), result.optString("name"));
        } else {
          db.editGroupFromServer(id, result.optString("email"), result.optString("name"));
          db.deleteMemberships(id);
        }

        JSONArray members = result.getJSONArray("members");

        for (int i = 0; i < members.length(); i++) {
          JSONObject o = members.getJSONObject(i);
          db.addMembership(
              o.getString("email"), id, (o.getString("accepted").equals("true")), false);
        }
      }
    } catch (ClientProtocolException e) {
      Log.e(Mapp.TAG, e.getMessage());
      throw new SyncException("Epic HTTP failure");
    } catch (IOException e) {
      Log.e(Mapp.TAG, e.getMessage());
      throw new SyncException("Exception during server synchronisation");
    } catch (JSONException e) {
      Log.e(Mapp.TAG, "Sync failed. Response is no valid JSON or expected variable not found.");
      throw new SyncException("Invalid server response");
    }
  }
  /**
   * Stuurt alle nieuwe polygonen naar de server
   *
   * @throws SyncException
   */
  private void putGroups() throws SyncException {
    Cursor c = db.getNewGroups();
    String name = "";
    int id = 0;

    if (!c.moveToFirst()) {
      return; // Niks te syncen, dus gelijk klaar!
    }

    /**
     * Als er tijdens het syncen een andere groep een ander id krijgt (omdat zijn id nodig was),
     * klopt onze cursor misschien niet meer dus moeten we opnieuw query'en.
     */
    boolean requery = false;

    do {
      HttpPut httpp = new HttpPut(serverUrl + "group");
      UsernamePasswordCredentials creds = new UsernamePasswordCredentials(mappUser, mappPass);

      id = c.getInt(0);
      name = c.getString(1);

      List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
      nameValuePairs.add(new BasicNameValuePair("name", name));

      try {
        httpp.addHeader(new BasicScheme().authenticate(creds, httpp));
        httpp.setEntity(new UrlEncodedFormEntity(nameValuePairs));
      } catch (AuthenticationException e1) {
        Log.e(Mapp.TAG, e1.getStackTrace().toString());
        throw new SyncException("Authentication failed");
      } catch (UnsupportedEncodingException e) {
        Log.e(Mapp.TAG, e.getStackTrace().toString());
        throw new SyncException("Failed to encode data");
      }

      HttpResponse response;

      try {
        response = httpclient.execute(httpp);

        // Lees het resultaat van de actie in
        JSONObject result = null;
        InputStream is = response.getEntity().getContent();
        BufferedReader r = new BufferedReader(new InputStreamReader(is));
        StringBuilder total = new StringBuilder();
        String line;
        while ((line = r.readLine()) != null) {
          total.append(line);
        }

        result = new JSONObject(total.toString());

        if (response.getStatusLine().getStatusCode() == 418) {
          throw new SyncException("Unable to synchronize because the server is a teapot.");
        } else if (response.getStatusLine().getStatusCode() == 401) {
          throw new SyncException("Not authorized");
        } else if (response.getStatusLine().getStatusCode() != 200) {
          // Er is iets mis gegaan.
          Log.e(Mapp.TAG, "Sync error: " + result.getString("message"));
          throw new SyncException(result.getString("message"));
        } else {
          // De polygoon een nieuw id geven en het 'nieuw'-vlaggetje verwijderen
          db.setGroupIsSynced(id);
          requery = db.updateGroupId(id, result.getInt("group_id"));
        }
      } catch (ClientProtocolException e) {
        Log.e(Mapp.TAG, e.getMessage());
        throw new SyncException("Epic HTTP failure");
      } catch (IOException e) {
        Log.e(Mapp.TAG, e.getMessage());
        throw new SyncException("Exception during server synchronisation");
      } catch (JSONException e) {
        Log.e(Mapp.TAG, "Sync failed. Response is no valid JSON or expected variable not found.");
        throw new SyncException("Invalid server response");
      }

      if (requery) {
        c = db.getNewGroups(); // Opnieuw laden omdat polygoonid's gewijzigd kunnen zijn inmiddels
      }
    } while (c.moveToNext());
  }
  /**
   * Werkt groepen bij
   *
   * @throws SyncException
   */
  private void updateGroups() throws SyncException {
    // Alle groepen die nog wel lokaal staan, maar waar volgens de server de gebruiker niet meer in
    // zit,
    // keihard wegmikken.
    Cursor c = db.getGroups();
    if (!c.moveToFirst()) {
      return; // Snel klaar.
    }

    // Checken welke groepen op de server aangemeld zijn
    HttpGet httpg = new HttpGet(serverUrl + "user");
    UsernamePasswordCredentials creds = new UsernamePasswordCredentials(mappUser, mappPass);

    try {
      httpg.addHeader(new BasicScheme().authenticate(creds, httpg));
    } catch (AuthenticationException e1) {
      Log.e(Mapp.TAG, e1.getMessage());
      throw new SyncException("Authentication failed");
    }

    HttpResponse response;
    ArrayList<Integer> groupsOnServer = new ArrayList<Integer>();

    try {
      response = httpclient.execute(httpg);

      // Lees het resultaat van de actie in
      InputStream is = response.getEntity().getContent();
      BufferedReader r = new BufferedReader(new InputStreamReader(is));
      StringBuilder total = new StringBuilder();
      String line;
      while ((line = r.readLine()) != null) {
        total.append(line);
      }

      if (response.getStatusLine().getStatusCode() == 418) {
        throw new SyncException("Unable to synchronize because the server is a teapot.");
      } else if (response.getStatusLine().getStatusCode() == 401) {
        throw new SyncException("Not authorized");
      } else if (response.getStatusLine().getStatusCode() != 200) {
        // Er is iets mis gegaan.
        JSONObject result = new JSONObject(total.toString());
        Log.e(Mapp.TAG, "Sync error: " + result.getString("message"));
        throw new SyncException(result.getString("message"));
      } else {
        // Alles is blijkbaar goed gegaan
        JSONObject result = new JSONObject(total.toString());
        JSONArray groups = result.getJSONArray("groups");
        // TODO GET memberships
        for (int i = 0; i < groups.length(); i++) {
          JSONObject o = groups.getJSONObject(i);
          groupsOnServer.add(o.getInt("id"));
        }
      }
    } catch (ClientProtocolException e) {
      Log.e(Mapp.TAG, e.getMessage());
      throw new SyncException("Epic HTTP failure");
    } catch (IOException e) {
      Log.e(Mapp.TAG, e.getMessage());
      throw new SyncException("Exception during server synchronisation");
    } catch (JSONException e) {
      Log.e(Mapp.TAG, "Sync failed. Response is no valid JSON or expected variable not found.");
      throw new SyncException("Invalid server response");
    }

    // Alles verwijderen wat niet meer op de server zit
    ArrayList<Integer> groupsInDb = new ArrayList<Integer>();

    do {
      groupsInDb.add(c.getInt(0));
      if (!groupsOnServer.contains(c.getInt(0))) {
        groupsInDb.remove(new Integer(c.getInt(0)));
        db.removePolygonsFromGroup(c.getInt(0), false);
        db.deleteMemberships(c.getInt(0));
        db.removeGroup(c.getInt(0), false);
      }
    } while (c.moveToNext());

    // En nu alles toevoegen wat nog niet lokaal zit / updaten
    for (int i : groupsOnServer) {
      updateGroup(i, groupsInDb.contains(i));
    }
  }
  /**
   * Synchroniseert gewijzigde polygonen met de server
   *
   * @param group het id van de groep waaruit polygonen gesynct moeten worden
   * @throws SyncException
   */
  private void getPolygons(int group, long lastSync) throws SyncException {
    HttpGet httpg = new HttpGet(serverUrl + "polygons/group_id/" + group + "/since/" + lastSync);
    UsernamePasswordCredentials creds = new UsernamePasswordCredentials(mappUser, mappPass);

    try {
      httpg.addHeader(new BasicScheme().authenticate(creds, httpg));
    } catch (AuthenticationException e1) {
      Log.e(Mapp.TAG, e1.getMessage());
      throw new SyncException("Authentication failed");
    }

    HttpResponse response;

    try {
      response = httpclient.execute(httpg);

      // Lees het resultaat van de actie in
      InputStream is = response.getEntity().getContent();
      BufferedReader r = new BufferedReader(new InputStreamReader(is));
      StringBuilder total = new StringBuilder();
      String line;
      while ((line = r.readLine()) != null) {
        total.append(line);
      }

      if (response.getStatusLine().getStatusCode() == 418) {
        throw new SyncException("Unable to synchronize because the server is a teapot.");
      } else if (response.getStatusLine().getStatusCode() == 401) {
        throw new SyncException("Not authorized");
      } else if (response.getStatusLine().getStatusCode() == 404) {
        // Geen nieuwe polygonen hier
        return;
      } else if (response.getStatusLine().getStatusCode() != 200) {
        // Er is iets mis gegaan.
        JSONObject result = new JSONObject(total.toString());
        Log.e(Mapp.TAG, "Sync error: " + result.getString("message"));
        throw new SyncException(result.getString("message"));
      } else {
        // Alles is blijkbaar goed gegaan
        JSONArray result = new JSONArray(total.toString());

        // Loop over de polygonen heen
        for (int i = 0; i < result.length(); i++) {
          JSONObject polygon = result.getJSONObject(i);

          // Deze polygoon is nieuw of gewijzigd dus we updaten 'm of voeren 'm in
          db.addPolygonFromServer(
              polygon.getInt("id"),
              polygon.getInt("group_id"),
              polygon.getInt("color"),
              polygon.getString("name"),
              polygon.optString("description"),
              polygon.getLong("created"));

          // Nu de punten invoeren
          JSONArray points = result.getJSONObject(i).getJSONArray("points");
          for (int j = 0; j < points.length(); j++) {
            JSONObject point = points.getJSONObject(j);
            db.addPolygonPoint(
                polygon.getInt("id"),
                point.getLong("latitude"),
                point.getLong("longitude"),
                point.getInt("order"),
                false);
          }
        }
      }
    } catch (ClientProtocolException e) {
      Log.e(Mapp.TAG, e.getMessage());
      throw new SyncException("Epic HTTP failure");
    } catch (IOException e) {
      Log.e(Mapp.TAG, e.getMessage());
      throw new SyncException("Exception during server synchronisation");
    } catch (JSONException e) {
      Log.e(Mapp.TAG, "Sync failed. Response is no valid JSON or expected variable not found.");
      throw new SyncException("Invalid server response");
    }
  }
  /**
   * Verwijdert polygonen lokaal als ze niet meer op de server staan. Naam van deze methode (C)
   * Joost Maar de inhoud van deze methode wel (C) Mathijs
   *
   * @param polygonIds een lijstje met polygonid's die op de server voorkomen (in deze groep)
   * @throws SyncException
   */
  private void removeDeletedPolygons(int group) throws SyncException {
    Cursor c = db.getAllPolygons(group);
    if (!c.moveToFirst()) {
      return; // Lokale db is al leeg
    }

    // Lijstje maken met alle id's op de server
    ArrayList<Integer> polygonIds = new ArrayList<Integer>();

    HttpGet httpg = new HttpGet(serverUrl + "polygons/group_id/" + group + "/since/1");
    UsernamePasswordCredentials creds = new UsernamePasswordCredentials(mappUser, mappPass);

    try {
      httpg.addHeader(new BasicScheme().authenticate(creds, httpg));
    } catch (AuthenticationException e1) {
      Log.e(Mapp.TAG, e1.getMessage());
      throw new SyncException("Authentication failed");
    }

    HttpResponse response;

    try {
      response = httpclient.execute(httpg);

      // Lees het resultaat van de actie in
      InputStream is = response.getEntity().getContent();
      BufferedReader r = new BufferedReader(new InputStreamReader(is));
      StringBuilder total = new StringBuilder();
      String line;
      while ((line = r.readLine()) != null) {
        total.append(line);
      }

      if (response.getStatusLine().getStatusCode() == 418) {
        throw new SyncException("Unable to synchronize because the server is a teapot.");
      } else if (response.getStatusLine().getStatusCode() == 401) {
        throw new SyncException("Not authorized");
      } else if (response.getStatusLine().getStatusCode() == 404) {
        // Geen polygonen hier
        do {
          if (!(c.getInt(3) == 1)) {
            db.removePolygon(c.getInt(0), false);
          }
        } while (c.moveToNext());
        return;
      } else if (response.getStatusLine().getStatusCode() != 200) {
        // Er is iets mis gegaan.
        JSONObject result = new JSONObject(total.toString());
        Log.e(Mapp.TAG, "Sync error: " + result.getString("message"));
        throw new SyncException(result.getString("message"));
      } else {
        // Alles is blijkbaar goed gegaan
        JSONArray result = new JSONArray(total.toString());

        // Loop over de polygonen heen
        for (int i = 0; i < result.length(); i++) {
          JSONObject polygon = result.getJSONObject(i);
          polygonIds.add(polygon.getInt("id"));
        }
      }
    } catch (ClientProtocolException e) {
      Log.e(Mapp.TAG, e.getMessage());
      throw new SyncException("Epic HTTP failure");
    } catch (IOException e) {
      Log.e(Mapp.TAG, e.getMessage());
      throw new SyncException("Exception during server synchronisation");
    } catch (JSONException e) {
      Log.e(Mapp.TAG, "Sync failed. Response is no valid JSON or expected variable not found.");
      throw new SyncException("Invalid server response");
    }

    // Nu we eindelijk alle id's hebben, kijken of er in de lokale db id's voorkomen die niet in
    // onze nieuwe lijst zitten
    do {
      if (!polygonIds.contains(c.getInt(0)) && c.getInt(3) != 1) {
        db.removePolygon(c.getInt(0), false);
      }
    } while (c.moveToNext());
  }
  /**
   * Synchroniseert gewijzigde polygonen met de server
   *
   * @param group het id van de groep waaruit polygonen gesynct moeten worden
   * @throws SyncException
   */
  private void postPolygons(int group) throws SyncException {
    Cursor c = db.getChangedPolygons(group);
    int polygonid = 0;
    String name = "";
    String color = "";
    String desc = "";

    if (!c.moveToFirst()) {
      return; // Niks te syncen, dus gelijk klaar!
    }

    do {
      HttpPost httpp = new HttpPost(serverUrl + "polygon");
      UsernamePasswordCredentials creds = new UsernamePasswordCredentials(mappUser, mappPass);

      polygonid = c.getInt(0);
      name = c.getString(2);
      color = c.getString(1);
      desc = c.getString(3);

      List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
      nameValuePairs.add(new BasicNameValuePair("id", polygonid + ""));
      nameValuePairs.add(new BasicNameValuePair("name", name));
      nameValuePairs.add(new BasicNameValuePair("group_id", group + ""));
      nameValuePairs.add(new BasicNameValuePair("color", color));
      nameValuePairs.add(new BasicNameValuePair("description", desc));

      // Nu de punten van de polygoon ophalen en die bijvoegen
      Cursor points = db.getAllPolygonPoints(polygonid);
      if (!points.moveToFirst()) {
        // Hier klopt iets niet, de polygoon heeft geen punten!
        db.removePolygon(polygonid, true);
        return;
      }

      do {
        nameValuePairs.add(
            new BasicNameValuePair(
                "points[]",
                points.getString(0) + "," + points.getString(1) + "," + points.getString(2)));
      } while (points.moveToNext());

      try {
        httpp.addHeader(new BasicScheme().authenticate(creds, httpp));
        httpp.setEntity(new UrlEncodedFormEntity(nameValuePairs));
      } catch (AuthenticationException e1) {
        Log.e(Mapp.TAG, e1.getMessage());
        throw new SyncException("Authentication failed");
      } catch (UnsupportedEncodingException e) {
        Log.e(Mapp.TAG, e.getMessage());
        throw new SyncException("Failed to encode data");
      }

      HttpResponse response;

      try {
        response = httpclient.execute(httpp);

        if (response.getStatusLine().getStatusCode() == 418) {
          throw new SyncException("Unable to synchronize because the server is a teapot.");
        } else if (response.getStatusLine().getStatusCode() == 401) {
          throw new SyncException("Not authorized");
        } else if (response.getStatusLine().getStatusCode() != 200) {
          // Er is iets mis gegaan.

          // Lees het resultaat van de actie in
          JSONObject result = null;
          InputStream is = response.getEntity().getContent();
          BufferedReader r = new BufferedReader(new InputStreamReader(is));
          StringBuilder total = new StringBuilder();
          String line;
          while ((line = r.readLine()) != null) {
            total.append(line);
          }

          result = new JSONObject(total.toString());

          Log.e(Mapp.TAG, "Sync error: " + result.getString("message"));
          throw new SyncException(result.getString("message"));
        } else {
          db.setPolygonIsSynced(polygonid);
        }
      } catch (ClientProtocolException e) {
        Log.e(Mapp.TAG, e.getMessage());
        throw new SyncException("Epic HTTP failure");
      } catch (IOException e) {
        Log.e(Mapp.TAG, e.getMessage());
        throw new SyncException("Exception during server synchronisation");
      } catch (JSONException e) {
        Log.e(Mapp.TAG, "Sync failed. Response is no valid JSON or expected variable not found.");
        throw new SyncException("Invalid server response");
      }
    } while (c.moveToNext());
  }
Beispiel #14
0
  /**
   * Analyzes a response to check need for a followup.
   *
   * @param roureq the request and route.
   * @param response the response to analayze
   * @param context the context used for the current request execution
   * @return the followup request and route if there is a followup, or <code>null</code> if the
   *     response should be returned as is
   * @throws HttpException in case of a problem
   * @throws IOException in case of an IO problem
   */
  protected RoutedRequest handleResponse(
      RoutedRequest roureq, HttpResponse response, HttpContext context)
      throws HttpException, IOException {

    HttpRoute route = roureq.getRoute();
    HttpHost proxy = route.getProxyHost();
    RequestWrapper request = roureq.getRequest();

    HttpParams params = request.getParams();
    if (HttpClientParams.isRedirecting(params)
        && this.redirectHandler.isRedirectRequested(response, context)) {

      if (redirectCount >= maxRedirects) {
        throw new RedirectException("Maximum redirects (" + maxRedirects + ") exceeded");
      }
      redirectCount++;

      URI uri = this.redirectHandler.getLocationURI(response, context);

      HttpHost newTarget = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());

      HttpGet redirect = new HttpGet(uri);

      HttpRequest orig = request.getOriginal();
      redirect.setHeaders(orig.getAllHeaders());

      RequestWrapper wrapper = new RequestWrapper(redirect);
      wrapper.setParams(params);

      HttpRoute newRoute = determineRoute(newTarget, wrapper, context);
      RoutedRequest newRequest = new RoutedRequest(wrapper, newRoute);

      if (this.log.isDebugEnabled()) {
        this.log.debug("Redirecting to '" + uri + "' via " + newRoute);
      }

      return newRequest;
    }

    CredentialsProvider credsProvider =
        (CredentialsProvider) context.getAttribute(ClientContext.CREDS_PROVIDER);

    if (credsProvider != null && HttpClientParams.isAuthenticating(params)) {

      if (this.targetAuthHandler.isAuthenticationRequested(response, context)) {

        HttpHost target = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
        if (target == null) {
          target = route.getTargetHost();
        }

        this.log.debug("Target requested authentication");
        Map<String, Header> challenges = this.targetAuthHandler.getChallenges(response, context);
        try {
          processChallenges(
              challenges, this.targetAuthState, this.targetAuthHandler, response, context);
        } catch (AuthenticationException ex) {
          if (this.log.isWarnEnabled()) {
            this.log.warn("Authentication error: " + ex.getMessage());
            return null;
          }
        }
        updateAuthState(this.targetAuthState, target, credsProvider);

        if (this.targetAuthState.getCredentials() != null) {
          // Re-try the same request via the same route
          return roureq;
        } else {
          return null;
        }
      } else {
        // Reset target auth scope
        this.targetAuthState.setAuthScope(null);
      }

      if (this.proxyAuthHandler.isAuthenticationRequested(response, context)) {

        this.log.debug("Proxy requested authentication");
        Map<String, Header> challenges = this.proxyAuthHandler.getChallenges(response, context);
        try {
          processChallenges(
              challenges, this.proxyAuthState, this.proxyAuthHandler, response, context);
        } catch (AuthenticationException ex) {
          if (this.log.isWarnEnabled()) {
            this.log.warn("Authentication error: " + ex.getMessage());
            return null;
          }
        }
        updateAuthState(this.proxyAuthState, proxy, credsProvider);

        if (this.proxyAuthState.getCredentials() != null) {
          // Re-try the same request via the same route
          return roureq;
        } else {
          return null;
        }
      } else {
        // Reset proxy auth scope
        this.proxyAuthState.setAuthScope(null);
      }
    }
    return null;
  } // handleResponse
Beispiel #15
0
  /**
   * Creates a tunnel to the target server. The connection must be established to the (last) proxy.
   * A CONNECT request for tunnelling through the proxy will be created and sent, the response
   * received and checked. This method does <i>not</i> update the connection with information about
   * the tunnel, that is left to the caller.
   *
   * @param route the route to establish
   * @param context the context for request execution
   * @return <code>true</code> if the tunnelled route is secure, <code>false</code> otherwise. The
   *     implementation here always returns <code>false</code>, but derived classes may override.
   * @throws HttpException in case of a problem
   * @throws IOException in case of an IO problem
   */
  protected boolean createTunnelToTarget(HttpRoute route, HttpContext context)
      throws HttpException, IOException {

    HttpHost proxy = route.getProxyHost();
    HttpHost target = route.getTargetHost();
    HttpResponse response = null;

    boolean done = false;
    while (!done) {

      done = true;

      if (!this.managedConn.isOpen()) {
        this.managedConn.open(route, context, this.params);
      }

      HttpRequest connect = createConnectRequest(route, context);

      String agent = HttpProtocolParams.getUserAgent(params);
      if (agent != null) {
        connect.addHeader(HTTP.USER_AGENT, agent);
      }
      connect.addHeader(HTTP.TARGET_HOST, target.toHostString());

      AuthScheme authScheme = this.proxyAuthState.getAuthScheme();
      AuthScope authScope = this.proxyAuthState.getAuthScope();
      Credentials creds = this.proxyAuthState.getCredentials();
      if (creds != null) {
        if (authScope != null || !authScheme.isConnectionBased()) {
          try {
            connect.addHeader(authScheme.authenticate(creds, connect));
          } catch (AuthenticationException ex) {
            if (this.log.isErrorEnabled()) {
              this.log.error("Proxy authentication error: " + ex.getMessage());
            }
          }
        }
      }

      response = requestExec.execute(connect, this.managedConn, context);

      int status = response.getStatusLine().getStatusCode();
      if (status < 200) {
        throw new HttpException(
            "Unexpected response to CONNECT request: " + response.getStatusLine());
      }

      CredentialsProvider credsProvider =
          (CredentialsProvider) context.getAttribute(ClientContext.CREDS_PROVIDER);

      if (credsProvider != null && HttpClientParams.isAuthenticating(params)) {
        if (this.proxyAuthHandler.isAuthenticationRequested(response, context)) {

          this.log.debug("Proxy requested authentication");
          Map<String, Header> challenges = this.proxyAuthHandler.getChallenges(response, context);
          try {
            processChallenges(
                challenges, this.proxyAuthState, this.proxyAuthHandler, response, context);
          } catch (AuthenticationException ex) {
            if (this.log.isWarnEnabled()) {
              this.log.warn("Authentication error: " + ex.getMessage());
              break;
            }
          }
          updateAuthState(this.proxyAuthState, proxy, credsProvider);

          if (this.proxyAuthState.getCredentials() != null) {
            done = false;

            // Retry request
            if (this.reuseStrategy.keepAlive(response, context)) {
              this.log.debug("Connection kept alive");
              // Consume response content
              HttpEntity entity = response.getEntity();
              if (entity != null) {
                entity.consumeContent();
              }
            } else {
              this.managedConn.close();
            }
          }

        } else {
          // Reset proxy auth scope
          this.proxyAuthState.setAuthScope(null);
        }
      }
    }

    int status = response.getStatusLine().getStatusCode();

    if (status > 299) {

      // Buffer response content
      HttpEntity entity = response.getEntity();
      if (entity != null) {
        response.setEntity(new BufferedHttpEntity(entity));
      }

      this.managedConn.close();
      throw new TunnelRefusedException(
          "CONNECT refused by proxy: " + response.getStatusLine(), response);
    }

    this.managedConn.markReusable();

    // How to decide on security of the tunnelled connection?
    // The socket factory knows only about the segment to the proxy.
    // Even if that is secure, the hop to the target may be insecure.
    // Leave it to derived classes, consider insecure by default here.
    return false;
  } // createTunnelToTarget