public boolean upload(String sourceFile, String destFile, String group, UserToken token) {

		if (destFile.charAt(0) != '/') {
			destFile = "/" + destFile;
		}

		try {
			Envelope message = null, response = null;
			message = new Envelope("UPLOADF");
			message.addObject(destFile);
			message.addObject(group);
			message.addObject(token); // Add requester's token
			output.writeObject(message);

			FileInputStream fis = new FileInputStream(sourceFile);

			response = (Envelope) input.readObject();

			if (response.getMessage().equals("READY")) {
				System.out.printf("Meta data upload successful\n");
			} else {
				System.out.printf("Upload failed: %s\n", response.getMessage());
				fis.close();
				return false;
			}

			do {
				byte[] buf = new byte[4096];
				if (response.getMessage().compareTo("READY") != 0) {
					System.out.printf("Server error: %s\n", response.getMessage());
					fis.close();
					return false;
				}
				message = new Envelope("CHUNK");
				int n = fis.read(buf); // can throw an IOException
				if (n > 0) {
					System.out.printf(".");
				} else if (n < 0) {
					System.out.println("Read error");
					fis.close();
					return false;
				}

				message.addObject(buf);
				message.addObject(new Integer(n));

				output.writeObject(message);
				response = (Envelope) input.readObject();

			} while (fis.available() > 0);
			fis.close();

			if (response.getMessage().compareTo("READY") == 0) {
				message = new Envelope("EOF");
				output.writeObject(message);

				response = (Envelope) input.readObject();
				if (response.getMessage().compareTo("OK") == 0) {
					System.out.printf("\nFile data upload successful\n");
				} else {
					System.out.printf("\nUpload failed: %s\n", response.getMessage());
					return false;
				}
			} else {
				System.out.printf("Upload failed: %s\n", response.getMessage());
				return false;
			}
		} catch (Exception e1) {
			System.err.println("Error: " + e1.getMessage());
			e1.printStackTrace(System.err);
			return false;
		}
		return true;
	}