- Timestamp:
- 06/03/09 05:40:24 PM (9 months ago)
- Files:
-
- 1 modified
Legend:
- Unmodified
- Added
- Removed
-
trunk/LogicMail/src/org/logicprobe/LogicMail/util/Connection.java
r381 r449 60 60 package org.logicprobe.LogicMail.util; 61 61 62 import net.rim.device.api.system.EventLogger; 63 import net.rim.device.api.ui.UiApplication; 64 import net.rim.device.api.ui.component.Dialog; 65 import net.rim.device.api.util.DataBuffer; 66 67 import org.logicprobe.LogicMail.AppInfo; 68 import org.logicprobe.LogicMail.conf.GlobalConfig; 69 import org.logicprobe.LogicMail.conf.MailSettings; 70 62 71 import java.io.IOException; 63 72 import java.io.InputStream; 64 73 import java.io.OutputStream; 74 65 75 import java.util.Vector; 76 77 import javax.microedition.io.Connector; 66 78 import javax.microedition.io.SocketConnection; 67 79 import javax.microedition.io.StreamConnection; 68 import javax.microedition.io.Connector; 69 import net.rim.device.api.system.EventLogger; 70 import net.rim.device.api.ui.UiApplication; 71 import net.rim.device.api.ui.component.Dialog; 72 import org.logicprobe.LogicMail.AppInfo; 73 import org.logicprobe.LogicMail.conf.GlobalConfig; 74 import org.logicprobe.LogicMail.conf.MailSettings; 80 75 81 76 82 /** … … 93 99 */ 94 100 public class Connection { 101 /** 102 * Byte array holding carriage return and line feed 103 */ 104 private static final byte[] CRLF = new byte[] { 13, 10 }; 105 106 /** 107 * Holds a list of open connections 108 */ 109 private static Vector openConnections = new Vector(); 95 110 private String serverName; 96 111 private int serverPort; … … 104 119 private boolean useWiFi; 105 120 private int fakeAvailable = -1; 106 107 /** 108 * Byte array holding carriage return and line feed 109 */ 110 private static final byte[] CRLF = new byte[] {13, 10}; 111 121 112 122 /** 113 123 * Provides a buffer used for incoming data. 114 124 */ 115 125 private byte[] buffer = new byte[128]; 116 117 /** 118 * Holds a list of open connections 119 */ 120 private static Vector openConnections = new Vector(); 121 122 public Connection(String serverName, int serverPort, boolean useSSL, boolean deviceSide) { 126 127 /** 128 * Provides a dynamic buffer for building results 129 */ 130 DataBuffer resultBuffer = new DataBuffer(); 131 132 public Connection(String serverName, int serverPort, boolean useSSL, 133 boolean deviceSide) { 123 134 this.serverName = serverName; 124 135 this.serverPort = serverPort; … … 130 141 this.globalConfig = MailSettings.getInstance().getGlobalConfig(); 131 142 } 132 143 133 144 /** 134 145 * Opens a connection. 135 146 */ 136 public void open() throws IOException {137 if (input != null || output != null || socket != null) {147 public synchronized void open() throws IOException { 148 if ((input != null) || (output != null) || (socket != null)) { 138 149 close(); 139 150 } 140 151 141 synchronized (openConnections) {142 if (!openConnections.contains(this)) {152 synchronized (openConnections) { 153 if (!openConnections.contains(this)) { 143 154 openConnections.addElement(this); 144 155 } 145 156 } 146 157 147 158 String protocolStr = (useSSL ? "ssl" : "socket"); 159 148 160 // This parameter, which allows bypassing the MDS proxy, should probably 149 161 // be a global user configurable option … … 151 163 152 164 useWiFi = false; 153 if(globalConfig.getWifiMode() == GlobalConfig.WIFI_PROMPT) { 165 166 if (globalConfig.getWifiMode() == GlobalConfig.WIFI_PROMPT) { 154 167 UiApplication.getUiApplication().invokeAndWait(new Runnable() { 155 public void run() {156 useWiFi = (Dialog.ask(Dialog.D_YES_NO, "Connect through WiFi?") == Dialog.YES);157 }158 });159 }160 else if(globalConfig.getWifiMode() == GlobalConfig.WIFI_ALWAYS) {168 public void run() { 169 useWiFi = (Dialog.ask(Dialog.D_YES_NO, 170 "Connect through WiFi?") == Dialog.YES); 171 } 172 }); 173 } else if (globalConfig.getWifiMode() == GlobalConfig.WIFI_ALWAYS) { 161 174 useWiFi = true; 162 175 } 163 164 if (useWiFi) {176 177 if (useWiFi) { 165 178 paramStr = paramStr + ";interface=wifi"; 166 179 } 167 168 String connectStr = protocolStr + "://" + serverName + ":" + serverPort + paramStr; 169 170 if(EventLogger.getMinimumLevel() >= EventLogger.INFORMATION) { 171 String msg = "Opening connection:\r\n"+connectStr+"\r\n"; 172 EventLogger.logEvent(AppInfo.GUID, msg.getBytes(), EventLogger.INFORMATION); 173 } 174 175 socket = (StreamConnection)Connector.open(connectStr, Connector.READ_WRITE, true); 180 181 String connectStr = protocolStr + "://" + serverName + ":" + 182 serverPort + paramStr; 183 184 if (EventLogger.getMinimumLevel() >= EventLogger.INFORMATION) { 185 String msg = "Opening connection:\r\n" + connectStr + "\r\n"; 186 EventLogger.logEvent(AppInfo.GUID, msg.getBytes(), 187 EventLogger.INFORMATION); 188 } 189 190 socket = (StreamConnection) Connector.open(connectStr, 191 Connector.READ_WRITE, true); 176 192 input = socket.openDataInputStream(); 177 193 output = socket.openDataOutputStream(); 178 localAddress = ((SocketConnection) socket).getLocalAddress();179 180 if (EventLogger.getMinimumLevel() >= EventLogger.INFORMATION) {181 String msg = 182 "Connection established:\r\n"+183 "Socket: "+socket.getClass().toString()+"\r\n"+184 "Local address: "+localAddress+"\r\n";185 EventLogger.logEvent(AppInfo.GUID, msg.getBytes(),EventLogger.INFORMATION);186 } 187 } 188 194 localAddress = ((SocketConnection) socket).getLocalAddress(); 195 196 if (EventLogger.getMinimumLevel() >= EventLogger.INFORMATION) { 197 String msg = "Connection established:\r\n" + "Socket: " + 198 socket.getClass().toString() + "\r\n" + "Local address: " + 199 localAddress + "\r\n"; 200 EventLogger.logEvent(AppInfo.GUID, msg.getBytes(), 201 EventLogger.INFORMATION); 202 } 203 } 204 189 205 /** 190 206 * Closes a connection. 191 207 */ 192 public void close() throws IOException {208 public synchronized void close() throws IOException { 193 209 try { 194 if (input != null) {210 if (input != null) { 195 211 input.close(); 196 212 input = null; … … 199 215 input = null; 200 216 } 217 201 218 try { 202 if (output != null) {219 if (output != null) { 203 220 output.close(); 204 221 output = null; … … 207 224 output = null; 208 225 } 226 209 227 try { 210 if (socket != null) {228 if (socket != null) { 211 229 socket.close(); 212 230 socket = null; … … 216 234 } 217 235 218 synchronized (openConnections) {219 if (openConnections.contains(this)) {236 synchronized (openConnections) { 237 if (openConnections.contains(this)) { 220 238 openConnections.removeElement(this); 221 239 } 222 240 } 223 224 EventLogger.logEvent(AppInfo.GUID, "Connection closed".getBytes(), EventLogger.INFORMATION); 225 } 226 241 242 EventLogger.logEvent(AppInfo.GUID, "Connection closed".getBytes(), 243 EventLogger.INFORMATION); 244 } 245 227 246 /** 228 247 * Determine whether open connections exist … … 232 251 public static boolean hasOpenConnections() { 233 252 boolean result; 234 synchronized(openConnections) { 253 254 synchronized (openConnections) { 235 255 result = !openConnections.isEmpty(); 236 256 } 257 237 258 return result; 238 259 } 239 260 240 261 /** 241 262 * Close all open connections 242 263 */ 243 264 public static void closeAllConnections() { 244 synchronized (openConnections) {265 synchronized (openConnections) { 245 266 int size = openConnections.size(); 246 for(int i = 0; i < size; i++) { 267 268 for (int i = 0; i < size; i++) { 247 269 try { 248 ((Connection)openConnections.elementAt(i)).close(); 249 } catch (IOException e) { } 250 } 270 ((Connection) openConnections.elementAt(i)).close(); 271 } catch (IOException e) { 272 } 273 } 274 251 275 openConnections.removeAllElements(); 252 276 } 253 277 } 254 278 255 279 /** 256 280 * Determine whether we are currently connected … … 258 282 */ 259 283 public boolean isConnected() { 260 if (socket != null)284 if (socket != null) { 261 285 return true; 262 else286 } else { 263 287 return false; 264 } 265 288 } 289 } 290 266 291 /** 267 292 * Get the local address to which this connection is bound … … 271 296 return localAddress; 272 297 } 273 298 274 299 /** 275 300 * Get the server name used when this connection was created … … 279 304 return serverName; 280 305 } 281 306 282 307 /** 283 308 * Sends a string to the server. This method is used internally for … … 289 314 * @see #receive 290 315 */ 291 public void send(String s) throws IOException {316 public synchronized void send(String s) throws IOException { 292 317 byte[] bytes = s.getBytes(); 293 318 int length = bytes.length; 294 319 295 320 /** 296 321 * Special case for empty strings: Only CR/LF is sent. 297 322 */ 298 323 if (s.length() == 0) { 299 if(globalConfig.getConnDebug()) { 300 EventLogger.logEvent(AppInfo.GUID, "[SEND]".getBytes(), EventLogger.DEBUG_INFO); 301 } 302 324 if (globalConfig.getConnDebug()) { 325 EventLogger.logEvent(AppInfo.GUID, "[SEND]".getBytes(), 326 EventLogger.DEBUG_INFO); 327 } 328 303 329 output.write(CRLF, 0, 2); 304 330 } … … 308 334 else { 309 335 int i = 0; 336 310 337 while (i < length) { 311 338 int j = i; 312 339 313 340 /** 314 341 * Find next occurrence of a line separator or the end of the 315 342 * string. 316 343 */ 317 while ((j < length) && (bytes[j] != 0x0A) && (bytes[j] != 0x0D)) { 344 while ((j < length) && (bytes[j] != 0x0A) && 345 (bytes[j] != 0x0D)) { 318 346 j++; 319 347 } 320 321 if(globalConfig.getConnDebug()) { 322 EventLogger.logEvent(AppInfo.GUID, ("[SEND] " + s.substring(i, j)).getBytes(), EventLogger.DEBUG_INFO); 323 } 324 348 349 if (globalConfig.getConnDebug()) { 350 EventLogger.logEvent(AppInfo.GUID, 351 ("[SEND] " + s.substring(i, j)).getBytes(), 352 EventLogger.DEBUG_INFO); 353 } 354 325 355 /** 326 356 * Write the string up to there and terminate it properly. 327 357 */ 328 output.write((s.substring(i, j) +"\r\n").getBytes());329 358 output.write((s.substring(i, j) + "\r\n").getBytes()); 359 330 360 /** 331 361 * If we stopped at a CR, ignore a possibly following LF. 332 362 */ 333 if ((j < length - 1) && (bytes[j] == 0x0D) && (bytes[j + 1] == 0x0A)) { 363 if ((j < (length - 1)) && (bytes[j] == 0x0D) && 364 (bytes[j + 1] == 0x0A)) { 334 365 j++; 335 366 } 336 367 337 368 i = j + 1; 338 369 } 339 370 } 371 340 372 output.flush(); 341 373 } 342 374 343 375 /** 344 376 * Sends a string to the server, terminating it with a CRLF. … … 346 378 * is a prepared protocol command. 347 379 */ 348 public void sendCommand(String s) throws IOException { 349 if(globalConfig.getConnDebug()) { 350 EventLogger.logEvent(AppInfo.GUID, ("[SEND CMD] " + s).getBytes(), EventLogger.DEBUG_INFO); 351 } 352 353 if(s == null) { 380 public synchronized void sendCommand(String s) throws IOException { 381 if (globalConfig.getConnDebug()) { 382 EventLogger.logEvent(AppInfo.GUID, ("[SEND CMD] " + s).getBytes(), 383 EventLogger.DEBUG_INFO); 384 } 385 386 if (s == null) { 354 387 output.write(CRLF, 0, 2); 355 } 356 else {357 output.write((s+"\r\n").getBytes());358 } 388 } else { 389 output.write((s + "\r\n").getBytes()); 390 } 391 359 392 output.flush(); 360 393 } 361 394 362 395 /** 363 396 * Sends a string to the server. This method is used to bypass all … … 368 401 * @see #send 369 402 */ 370 public void sendRaw(String s) throws IOException {403 public synchronized void sendRaw(String s) throws IOException { 371 404 byte[] bytes = s.getBytes(); 372 373 if(globalConfig.getConnDebug()) { 374 EventLogger.logEvent(AppInfo.GUID, ("[SEND RAW]\r\n" + s).getBytes(), EventLogger.DEBUG_INFO); 375 } 376 405 406 if (globalConfig.getConnDebug()) { 407 EventLogger.logEvent(AppInfo.GUID, 408 ("[SEND RAW]\r\n" + s).getBytes(), EventLogger.DEBUG_INFO); 409 } 410 377 411 output.write(bytes, 0, bytes.length); 378 412 379 413 output.flush(); 380 414 } … … 383 417 * Returns the number of bytes available for reading. 384 418 * Used to poll the connection without blocking. 385 * 419 * 386 420 * @see InputStream#available() 387 421 */ 388 422 public int available() throws IOException { 389 if(fakeAvailable == -1) { 390 return input.available(); 391 } 392 else { 393 return fakeAvailable; 394 } 395 } 396 423 if (fakeAvailable == -1) { 424 return input.available(); 425 } else { 426 return fakeAvailable; 427 } 428 } 429 397 430 /** 398 431 * Receives a string from the server. This method is used internally for … … 404 437 * @see #send 405 438 */ 406 public String receive() throws IOException {439 public synchronized String receive() throws IOException { 407 440 /** 408 441 * A note on how this method works and why it is designed the … … 432 465 * but there's not much one can about that. 433 466 */ 434 StringBuffer resultBuffer = new StringBuffer();435 467 boolean stop = false; 468 resultBuffer.reset(); 469 436 470 int actualAvailable = input.available(); 437 471 int readBytes = 0; 438 472 int count; 439 473 440 474 /** 441 475 * The "stop" flag will be set as soon as we have received … … 445 479 while (!stop) { 446 480 count = 0; 447 481 448 482 /** 449 483 * The inner block reads single bytes from the InputStream … … 453 487 while (true) { 454 488 int actual = input.read(buffer, count, 1); 455 489 456 490 /** 457 491 * If -1 is returned, the InputStream is already closed, … … 461 495 */ 462 496 if (actual == -1) { 463 EventLogger.logEvent(AppInfo.GUID, "Unable to read from socket, closing connection".getBytes(), EventLogger.INFORMATION); 497 EventLogger.logEvent(AppInfo.GUID, 498 "Unable to read from socket, closing connection".getBytes(), 499 EventLogger.INFORMATION); 500 464 501 try { 465 502 close(); 466 } catch (IOException e) { } 467 503 } catch (IOException e) { 504 } 505 468 506 throw new IOException("Connection closed"); 469 507 } 470 471 508 /** 472 509 * If no bytes have been received, we wait a little … … 476 513 try { 477 514 Thread.yield(); 478 } catch (Exception e) { }479 }480 515 } catch (Exception e) { 516 } 517 } 481 518 /** 482 519 * If a byte has been read, examine it and put it in the 483 520 * buffer. 484 521 */ 522 485 523 // Note: We really should look for CRLF, and not use this 486 524 // approach which screws up on mid-line LFs. (DK) … … 488 526 byte b = buffer[count]; 489 527 readBytes++; 490 528 491 529 /** 492 530 * Ignore all CRs. … … 500 538 else if (b == 0x0A) { 501 539 stop = true; 540 502 541 break; 503 542 } … … 507 546 else { 508 547 count++; 548 509 549 if (count == buffer.length) { 510 550 break; … … 513 553 } 514 554 } 515 resultBuffer.append(new String(buffer, 0, count)); 516 } 517 518 if(globalConfig.getConnDebug()) { 519 EventLogger.logEvent(AppInfo.GUID, ("[RECV] " + resultBuffer.toString()).getBytes(), EventLogger.DEBUG_INFO); 520 } 521 if(actualAvailable > readBytes) { 522 fakeAvailable = actualAvailable - readBytes; 523 } 524 else { 525 fakeAvailable = -1; 526 } 527 528 return resultBuffer.toString(); 555 556 resultBuffer.write(buffer, 0, count); 557 } 558 559 String result = new String(resultBuffer.toArray()); 560 561 if (globalConfig.getConnDebug()) { 562 EventLogger.logEvent(AppInfo.GUID, 563 ("[RECV] " + result).getBytes(), 564 EventLogger.DEBUG_INFO); 565 } 566 567 if (actualAvailable > readBytes) { 568 fakeAvailable = actualAvailable - readBytes; 569 } else { 570 fakeAvailable = -1; 571 } 572 573 return result; 529 574 } 530 575 } 531
