import java.net.UnknownHostException;
import java.security.InvalidParameterException;
import java.util.Date;
+import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.ResourceBundle;
import be.nikiroo.jvcard.Card;
import be.nikiroo.jvcard.Data;
import be.nikiroo.jvcard.parsers.Format;
import be.nikiroo.jvcard.parsers.Vcard21Parser;
-import be.nikiroo.jvcard.remote.Command.Verb;
import be.nikiroo.jvcard.resources.Bundles;
import be.nikiroo.jvcard.resources.StringUtils;
private List<SimpleSocket> clients = new LinkedList<SimpleSocket>();
private Object updateLock = new Object();
+ private Map<File, Integer> updates = new HashMap<File, Integer>();
/**
* Create a new jVCard server on the given port.
SimpleSocket c = new SimpleSocket(new Socket((String) null, port),
"special STOP client");
c.open(true);
- c.sendCommand(Verb.STOP);
+ c.sendCommand(Command.STOP);
c.close();
} catch (UnknownHostException e) {
e.printStackTrace();
}
/**
- * Process a command.
+ * Process a first-level command.
*
* @param s
* the {@link SimpleSocket} from which to get the command to
* in case of IO error
*/
private boolean processCmd(SimpleSocket s) throws IOException {
- Command cmd = s.receiveCommand();
- Command.Verb verb = cmd.getVerb();
+ CommandInstance cmd = s.receiveCommand();
+ Command command = cmd.getCommand();
- if (verb == null)
+ if (command == null)
return false;
boolean clientContinue = true;
- System.out.println(s + " -> " + verb);
+ System.out.println(s + " -> " + command
+ + (cmd.getParam() == null ? "" : " " + cmd.getParam()));
- switch (verb) {
- case STOP:
+ switch (command) {
+ case STOP: {
clientContinue = false;
break;
- case VERSION:
- s.sendCommand(Verb.VERSION);
+ }
+ case VERSION: {
+ s.sendLine("" + SimpleSocket.CURRENT_VERSION);
break;
- case TIME:
+ }
+ case TIME: {
s.sendLine(StringUtils.fromTime(new Date().getTime()));
break;
- case GET_CARD:
- synchronized (updateLock) {
- s.sendBlock(doGetCard(cmd.getParam()));
- }
- break;
- case POST_CARD:
- synchronized (updateLock) {
- s.sendLine(doPostCard(cmd.getParam(), s.receiveBlock()));
- }
- break;
- case PUT_CARD:
- synchronized (updateLock) {
- File vcf = getFile(cmd.getParam());
- if (vcf == null) {
- System.err
- .println("Fail to update a card, file not available: "
- + cmd.getParam());
- clientContinue = false;
- } else {
- Card card = new Card(vcf, Format.VCard21);
+ }
+ case SELECT: {
+ String name = cmd.getParam();
+ File file = new File(dataDir.getAbsolutePath() + File.separator
+ + name);
+ if (name == null || name.length() == 0 || !file.exists()) {
+ System.err
+ .println("SELECT: resource not found, closing connection: "
+ + name);
+ clientContinue = false;
+ } else {
+ synchronized (updateLock) {
+ for (File f : updates.keySet()) {
+ if (f.getCanonicalPath()
+ .equals(file.getCanonicalPath())) {
+ file = f;
+ break;
+ }
+ }
+
+ if (!updates.containsKey(file))
+ updates.put(file, 0);
+ updates.put(file, updates.get(file) + 1);
+ }
+
+ synchronized (file) {
try {
- while (processContactCmd(s, card))
+ s.sendLine(StringUtils.fromTime(file.lastModified()));
+
+ while (processLockedCmd(s, name))
;
- card.save();
} catch (InvalidParameterException e) {
System.err
.println("Unsupported command received from a client connection, closing it: "
- + verb + " (" + e.getMessage() + ")");
+ + command + " (" + e.getMessage() + ")");
clientContinue = false;
}
}
+
+ synchronized (updateLock) {
+ int num = updates.get(file) - 1;
+ if (num == 0) {
+ updates.remove(file);
+ } else {
+ updates.put(file, num);
+ }
+ }
}
break;
- case DELETE_CARD:
- // TODO
- System.err
- .println("Unsupported command received from a client connection, closing it: "
- + verb);
- clientContinue = false;
- break;
- case LIST:
+ }
+ case LIST_CARD: {
for (File file : dataDir.listFiles()) {
- if (cmd.getParam() == null || cmd.getParam().length() == 0
- || file.getName().contains(cmd.getParam())) {
+ if (cmd.getParam() == null
+ || cmd.getParam().length() == 0
+ || file.getName().toLowerCase()
+ .contains(cmd.getParam().toLowerCase())) {
s.send(StringUtils.fromTime(file.lastModified()) + " "
+ file.getName());
}
}
s.sendBlock();
break;
- case HELP:
+ }
+ case HELP: {
// TODO: i18n
s.send("The following commands are available:");
s.send("- TIME: get the server time");
s.send("- HELP: this help screen");
- s.send("- LIST: list the available cards on this server");
- s.send("- VERSION/GET/PUT/POST/DELETE/STOP: TODO");
+ s.send("- LIST_CARD: list the available cards on this server");
+ s.send("- VERSION/GET_*/PUT_*/POST_*/DELETE_*/STOP: TODO");
s.sendBlock();
break;
- default:
+ }
+ default: {
System.err
.println("Unsupported command received from a client connection, closing it: "
- + verb);
+ + command);
clientContinue = false;
break;
}
+ }
+
+ return clientContinue;
+ }
+
+ /**
+ * Process a subcommand while protected for resource <tt>name</tt>.
+ *
+ * @param s
+ * the {@link SimpleSocket} to process
+ *
+ * @param name
+ * the resource that is protected (and to target)
+ *
+ * @return TRUE if the client is ready for another command, FALSE when the
+ * client is done
+ *
+ * @throws IOException
+ * in case of IO error
+ *
+ * @throw InvalidParameterException in case of invalid subcommand
+ */
+ private boolean processLockedCmd(SimpleSocket s, String name)
+ throws IOException {
+ CommandInstance cmd = s.receiveCommand();
+ Command command = cmd.getCommand();
+
+ if (command == null)
+ return false;
+
+ boolean clientContinue = true;
+
+ System.out.println(s + " -> " + command);
+
+ switch (command) {
+ case GET_CARD: {
+ s.sendBlock(doGetCard(name));
+ break;
+ }
+ case POST_CARD: {
+ s.sendLine(doPostCard(name, s.receiveBlock()));
+ break;
+ }
+ case PUT_CARD: {
+ File vcf = getFile(name);
+ if (vcf == null) {
+ System.err
+ .println("Fail to update a card, file not available: "
+ + name);
+ clientContinue = false;
+ } else {
+ Card card = new Card(vcf, Format.VCard21);
+ try {
+ while (processContactCmd(s, card))
+ ;
+ card.save();
+ s.sendLine(StringUtils.fromTime(card.getLastModified()));
+ } catch (InvalidParameterException e) {
+ System.err
+ .println("Unsupported command received from a client connection, closing it: "
+ + command + " (" + e.getMessage() + ")");
+ clientContinue = false;
+ }
+ }
+ break;
+ }
+ case DELETE_CARD: {
+ // TODO
+ System.err
+ .println("Unsupported command received from a client connection, closing it: "
+ + command);
+ clientContinue = false;
+ break;
+ }
+ case SELECT: {
+ clientContinue = false;
+ break;
+ }
+ default: {
+ throw new InvalidParameterException("command invalid here: "
+ + command);
+ }
+ }
return clientContinue;
}
*/
private boolean processContactCmd(SimpleSocket s, Card card)
throws IOException {
- Command cmd = s.receiveCommand();
- Command.Verb verb = cmd.getVerb();
+ CommandInstance cmd = s.receiveCommand();
+ Command command = cmd.getCommand();
- if (verb == null)
+ if (command == null)
return false;
boolean clientContinue = true;
- System.out.println(s + " -> " + verb);
+ System.out.println(s + " -> " + command);
- switch (verb) {
+ switch (command) {
case GET_CONTACT: {
Contact contact = card.getById(cmd.getParam());
if (contact != null)
break;
}
case POST_CONTACT: {
- String uid = cmd.getParam();
- Contact contact = card.getById(uid);
- if (contact != null)
- contact.delete();
List<Contact> list = Vcard21Parser.parseContact(s.receiveBlock());
if (list.size() > 0) {
- contact = list.get(0);
- contact.getPreferredData("UID").setValue(uid);
- card.add(contact);
+ Contact newContact = list.get(0);
+ String uid = newContact.getPreferredDataValue("UID");
+ Contact oldContact = card.getById(uid);
+ if (oldContact != null)
+ oldContact.delete();
+ card.add(newContact);
}
+
break;
}
case PUT_CONTACT: {
contact.delete();
break;
}
+ case HASH_CONTACT: {
+ String uid = cmd.getParam();
+ Contact contact = card.getById(uid);
+
+ if (contact == null) {
+ s.sendBlock();
+ } else {
+ s.sendLine(contact.getContentState());
+ }
+ break;
+ }
+ case LIST_CONTACT: {
+ for (Contact contact : card) {
+ if (cmd.getParam() == null
+ || cmd.getParam().length() == 0
+ || (contact.getPreferredDataValue("FN") + contact
+ .getPreferredDataValue("N")).toLowerCase()
+ .contains(cmd.getParam().toLowerCase())) {
+ s.send(contact.getContentState() + " " + contact.getId());
+ }
+ }
+ s.sendBlock();
+ break;
+ }
case PUT_CARD: {
clientContinue = false;
break;
}
default: {
- throw new InvalidParameterException("command invalid here");
+ throw new InvalidParameterException("command invalid here: "
+ + command);
}
}
*/
private boolean processDataCmd(SimpleSocket s, Contact contact)
throws IOException {
- Command cmd = s.receiveCommand();
- Command.Verb verb = cmd.getVerb();
+ CommandInstance cmd = s.receiveCommand();
+ Command command = cmd.getCommand();
- if (verb == null)
+ if (command == null)
return false;
boolean clientContinue = true;
- System.out.println(s + " -> " + verb);
+ System.out.println(s + " -> " + command);
- switch (verb) {
+ switch (command) {
case GET_DATA: {
- Data data = contact.getById(cmd.getParam());
- if (data != null)
- s.sendBlock(Vcard21Parser.toStrings(data));
- else
- s.sendBlock();
+ for (Data data : contact) {
+ if (data.getName().equals(cmd.getParam())) {
+ for (String line : Vcard21Parser.toStrings(data)) {
+ s.send(line);
+ }
+ }
+ }
+ s.sendBlock();
break;
}
case POST_DATA: {
contact.delete();
break;
}
+ case HASH_DATA: {
+ for (Data data : contact) {
+ if (data.getId().equals(cmd.getParam())) {
+ s.send(data.getContentState());
+ }
+ }
+ s.sendBlock();
+ break;
+ }
+ case LIST_DATA: {
+ for (Data data : contact) {
+ if (cmd.getParam() == null
+ || cmd.getParam().length() == 0
+ || data.getName().toLowerCase()
+ .contains(cmd.getParam().toLowerCase())) {
+ s.send(data.getContentState() + " " + data.getName());
+ }
+ }
+ s.sendBlock();
+ break;
+ }
case PUT_CONTACT: {
clientContinue = false;
break;
}
default: {
- throw new InvalidParameterException("command invalid here");
+ throw new InvalidParameterException("command invalid here: "
+ + command);
}
}
if (vcf != null && vcf.exists()) {
Card card = new Card(vcf, Format.VCard21);
- // timestamp:
+ // timestamp + data
lines.add(StringUtils.fromTime(card.getLastModified()));
lines.addAll(Vcard21Parser.toStrings(card));
}