package org.bitseal.controllers;
import java.util.ArrayList;
import org.bitseal.core.App;
import org.bitseal.core.PubkeyProcessor;
import org.bitseal.crypt.PubkeyGenerator;
import org.bitseal.data.Address;
import org.bitseal.data.Payload;
import org.bitseal.data.Pubkey;
import org.bitseal.database.AddressProvider;
import org.bitseal.database.PayloadProvider;
import org.bitseal.database.PayloadsTable;
import org.bitseal.database.PubkeyProvider;
import org.bitseal.database.PubkeysTable;
import org.bitseal.util.ByteFormatter;
import org.bitseal.util.TimeUtils;
import android.util.Log;
/**
* This class controls the operations necessary to check whether
* any of our pubkeys need to be disseminated to the Bitmessage
* network again, and to do so when that time comes.
*
* @author Jonathan Coe
*/
public class ReDisseminatePubkeysController
{
private static final String TAG = "RE_DISSEMINATE_PUBKEYS_CONTROLLER";
/**
* Checks whether any of our pubkeys are due to be disseminated again.
*
* @return An ArrayList<Address> containing any Addresses for which the Pubkeys
* have expired and are thus due to be disseminated again. If none are due, this
* ArrayList will be empty.
*/
public ArrayList<Address> checkIfPubkeyDisseminationIsDue()
{
// Get all the user's pubkeys
PubkeyProvider pubProv = PubkeyProvider.get(App.getContext());
ArrayList<Pubkey> myPubkeys = pubProv.searchPubkeys(PubkeysTable.COLUMN_BELONGS_TO_ME, String.valueOf(1)); // 1 stands for true in the database
// Check whether any of our pubkeys need to be disseminated again
ArrayList<Address> addressesWithExpiredPubkeys = new ArrayList<Address>();
for (Pubkey p : myPubkeys)
{
// Retrieve the Address object that corresponds to this pubkey
Address address = null;
try
{
address = AddressProvider.get(App.getContext()).searchForSingleRecord(p.getCorrespondingAddressId());
}
catch (RuntimeException e)
{
Log.e(TAG, "While running ReDisseminatePubkeysController.checkIfPubkeyDisseminationIsDue(), we were unable to find "
+ "a database record of the Address for the Pubkey with the ripe hash " + ByteFormatter.byteArrayToHexString(p.getRipeHash()) + ". "
+ "As the Pubkey is useless without its corresponding address, the Pubkey will now be deleted from the database.");
pubProv.deletePubkey(p);
continue;
}
// Work out whether the pubkey is due for re-dissemination
long currentTime = System.currentTimeMillis() / 1000;
long expirationTime = p.getExpirationTime();
if (expirationTime < currentTime)
{
long timeSinceExpiration = currentTime - expirationTime;
Log.d(TAG, "The pubkey for address " + address.getAddress() + " expired " + TimeUtils.getTimeMessage(timeSinceExpiration) + " ago.\n" +
"We will now attempt to re-disseminate it.");
addressesWithExpiredPubkeys.add(address);
}
else
{
long timeTillExpiration = expirationTime - currentTime;
Log.i(TAG, "The pubkey for address " + address.getAddress() + " will expire and be due for re-dissemination in " + TimeUtils.getTimeMessage(timeTillExpiration));
}
}
return addressesWithExpiredPubkeys;
}
/**
* Creates an updated payload for pubkeys that need to be disseminated again.
*
* @param address - The Address which requires its pubkey to be regenerated
* @param doPOW - A boolean indicating whether or not to do POW for the updated
* pubkey payload
*
* @return The updated pubkey payload
*/
public Payload regeneratePubkey(Address address, boolean doPOW)
{
Log.d(TAG, "The pubkey for address " + address.getAddress() + " is due to be re-disseminated. This will be done now.");
// Delete the old pubkey
PubkeyProvider pubProv = PubkeyProvider.get(App.getContext());
Pubkey oldPubkey = null;
try
{
oldPubkey = pubProv.searchForSingleRecord(address.getCorrespondingPubkeyId());
}
catch (Exception e)
{
Log.e(TAG, "While running ReDisseminatePubkeysController.regeneratePubkey(), we were unable to retrieve the pubkey "
+ "with ID " + address.getCorrespondingPubkeyId() + ". The address with ID " + address.getId() + " and address " + address.getAddress() + " "
+ "has this pubkey registered as its corresponding pubkey. Skipping deletion, since the pubkey cannot be found.");
}
if (oldPubkey != null)
{
pubProv.deletePubkey(oldPubkey);
}
// Delete the old pubkey's corresponding Payload(s)
PayloadProvider payProv = PayloadProvider.get(App.getContext());
String [] columnNames = new String[]{PayloadsTable.COLUMN_TYPE, PayloadsTable.COLUMN_BELONGS_TO_ME, PayloadsTable.COLUMN_RELATED_ADDRESS_ID};
String[] selections = new String[]{Payload.OBJECT_TYPE_PUBKEY, "1", String.valueOf(address.getId())}; // 1 stands for true in the database
ArrayList<Payload> matchingPayloads = payProv.searchPayloads(columnNames, selections);
for (Payload p : matchingPayloads)
{
payProv.deletePayload(p);
}
// Generate a new pubkey
Pubkey regeneratedPubkey = new PubkeyGenerator().generateAndSaveNewPubkey(address);
// Create an updated payload for the pubkey. We can then re-disseminate it to the network.
return new PubkeyProcessor().constructPubkeyPayload(regeneratedPubkey, doPOW);
}
}