├── .gitignore
├── LICENSE
├── README.md
├── android-app
├── AndroidManifest.xml
├── libs
│ └── android-support-v4.jar
├── lint.xml
├── proguard-project.txt
├── project.properties
├── res
│ ├── drawable-hdpi
│ │ └── ic_launcher.png
│ ├── drawable-mdpi
│ │ └── ic_launcher.png
│ ├── drawable-xhdpi
│ │ └── ic_launcher.png
│ ├── layout
│ │ └── activity_mobile_chat.xml
│ ├── menu
│ │ └── main.xml
│ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
└── src
│ ├── com
│ └── codebutler
│ │ └── android_websockets
│ │ ├── HybiParser.java
│ │ └── WebSocketClient.java
│ └── nl
│ └── meta
│ └── mobile
│ └── chat
│ └── MobileChatActivity.java
├── ios-app
└── Mobile Chat
│ ├── Mobile Chat.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ ├── Mobile Chat
│ ├── AppDelegate.h
│ ├── AppDelegate.m
│ ├── Default-568h@2x.png
│ ├── Default.png
│ ├── Default@2x.png
│ ├── Mobile Chat-Info.plist
│ ├── Mobile Chat-Prefix.pch
│ ├── ViewController.h
│ ├── ViewController.m
│ ├── en.lproj
│ │ ├── InfoPlist.strings
│ │ ├── MainStoryboard_iPad.storyboard
│ │ └── MainStoryboard_iPhone.storyboard
│ └── main.m
│ └── SocketRocket-master
│ ├── .gitignore
│ ├── .gitmodules
│ ├── LICENSE
│ ├── README.rst
│ ├── SocketRocket.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── WorkspaceSettings.xcsettings
│ └── xcshareddata
│ │ └── xcschemes
│ │ ├── SocketRocket.xcscheme
│ │ ├── SocketRocketOSX.xcscheme
│ │ ├── SocketRocketTests.xcscheme
│ │ └── TestChat.xcscheme
│ └── SocketRocket
│ ├── NSData+SRB64Additions.h
│ ├── NSData+SRB64Additions.m
│ ├── SRWebSocket.h
│ ├── SRWebSocket.m
│ ├── SocketRocket-Prefix.pch
│ ├── base64.c
│ └── base64.h
├── nodejs-server
└── mobile-chat.js
├── webclient
├── box.css
├── index.html
└── mobile-chat.js
└── windows-phone-8
└── MobileChat
├── MobileChat.sln
└── MobileChat
├── App.xaml
├── App.xaml.cs
├── Assets
├── AlignmentGrid.png
├── ApplicationIcon.png
└── Tiles
│ ├── FlipCycleTileLarge.png
│ ├── FlipCycleTileMedium.png
│ ├── FlipCycleTileSmall.png
│ ├── IconicTileMediumLarge.png
│ └── IconicTileSmall.png
├── LocalizedStrings.cs
├── MobileChat.csproj
├── MobileChat.xaml
├── MobileChat.xaml.cs
├── Properties
├── AppManifest.xml
├── AssemblyInfo.cs
└── WMAppManifest.xml
├── Resources
├── AppResources.Designer.cs
└── AppResources.resx
└── libs
└── WebSocket4Net.dll
/.gitignore:
--------------------------------------------------------------------------------
1 | # built application files
2 | *.apk
3 | *.ap_
4 |
5 | # files for the dex VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # generated files
12 | bin/
13 | gen/
14 |
15 | # Local configuration file (sdk path, etc)
16 | local.properties
17 |
18 | # Eclipse project files
19 | .classpath
20 | .project
21 |
22 | # Proguard folder generated by Eclipse
23 | proguard/
24 |
25 | # Intellij project files
26 | *.iml
27 | *.ipr
28 | *.iws
29 | .idea/
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Mobile-Multiplatform-Websockets-Android-iOS-Windows-Phone-Web
2 | ==============
3 |
4 | Cross platform (Android, iOS, Windows Phone 8, web) chat supported by NodeJS websockets.
5 |
6 | Quick install
7 | ==============
8 |
9 | Server:
10 | Install Node.js http://nodejs.org/ with SockJS https://github.com/sockjs/sockjs-node on your server. Then run the mobile-chat.js in nodejs-server with the command node mobile-chat.js
.
11 |
12 | Webclient:
13 | Make all files available through an installed webserver, for example xampp.
14 | Remember to update the following line for your server.
15 |
16 | For the Webclient change: mobile-chat.js
17 | ```javascript
18 | //Connect to your server here
19 | var mobileChatSocket = new SockJS('http://your.server:6975/mobilechat');
20 | ```
21 |
22 | For Android change: MobileChatActivity.java
23 | ```java
24 | // This library requires a raw websocket url.
25 | // For NodeJS with SockJS this should be
26 | // "ws://YOUR.URL:PORT/IDENTIFIER/websocket"
27 | private final String CONSTANT_WEBSOCKETS_URL = "ws://your.site.nl:6975/mobilechat/websocket";
28 | ```
29 |
30 | For iOS change: ViewController.m
31 | ```objective-c
32 | //This library requires a raw websocket url. It does accept http instead of ws.
33 | //For NodeJS with SockJS this should be "http://YOUR.URL:PORT/IDENTIFIER/websocket"
34 | self.sockjsSocket = [[SRWebSocket alloc] initWithURL:[[NSURL alloc] initWithString:@"http://your.site:6975/mobilechat/websocket"]];
35 | ```
36 |
37 | For Windows Phone 8 change: MobileChat.xaml.cs
38 | ```c#
39 | //This library requires a raw websocket url.
40 | //For NodeJS with SockJS this should be "ws://YOUR.URL:PORT/IDENTIFIER/websocket"
41 | private readonly String webSocketLink = "ws://your.site:6975/mobilechat/websocket";
42 | ```
43 |
44 | Libraries used
45 | ==============
46 | * Web: SockJS
47 | * Android : Codebutler
48 | * IOS: SocketRocket
49 | * Windows phone 8: WebSocket4Net
50 |
--------------------------------------------------------------------------------
/android-app/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
19 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/android-app/libs/android-support-v4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TerryWahl/Mobile-Multiplatform-Websockets-Android-iOS-Windows-Phone-Web/10d3a2dc8947166040671affe8ec79e73ebca6f8/android-app/libs/android-support-v4.jar
--------------------------------------------------------------------------------
/android-app/lint.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/android-app/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/android-app/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-18
15 |
--------------------------------------------------------------------------------
/android-app/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TerryWahl/Mobile-Multiplatform-Websockets-Android-iOS-Windows-Phone-Web/10d3a2dc8947166040671affe8ec79e73ebca6f8/android-app/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android-app/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TerryWahl/Mobile-Multiplatform-Websockets-Android-iOS-Windows-Phone-Web/10d3a2dc8947166040671affe8ec79e73ebca6f8/android-app/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android-app/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TerryWahl/Mobile-Multiplatform-Websockets-Android-iOS-Windows-Phone-Web/10d3a2dc8947166040671affe8ec79e73ebca6f8/android-app/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android-app/res/layout/activity_mobile_chat.xml:
--------------------------------------------------------------------------------
1 |
21 |
22 |
31 |
32 |
40 |
41 |
49 |
50 |
51 |
52 |
53 |
62 |
63 |
68 |
69 |
70 |
71 |
72 |
73 |
81 |
82 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/android-app/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/android-app/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #99CC00
5 |
6 | #910000
7 |
8 |
--------------------------------------------------------------------------------
/android-app/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 16dp
5 | 16dp
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android-app/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Mobile Chat
5 | Settings
6 |
7 | Connected
8 | Not connected
9 |
10 |
11 |
--------------------------------------------------------------------------------
/android-app/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/android-app/src/com/codebutler/android_websockets/HybiParser.java:
--------------------------------------------------------------------------------
1 | //
2 | // HybiParser.java: draft-ietf-hybi-thewebsocketprotocol-13 parser
3 | //
4 | // Based on code from the faye project.
5 | // https://github.com/faye/faye-websocket-node
6 | // Copyright (c) 2009-2012 James Coglan
7 | //
8 | // Ported from Javascript to Java by Eric Butler
9 | //
10 | // (The MIT License)
11 | //
12 | // Permission is hereby granted, free of charge, to any person obtaining
13 | // a copy of this software and associated documentation files (the
14 | // "Software"), to deal in the Software without restriction, including
15 | // without limitation the rights to use, copy, modify, merge, publish,
16 | // distribute, sublicense, and/or sell copies of the Software, and to
17 | // permit persons to whom the Software is furnished to do so, subject to
18 | // the following conditions:
19 | //
20 | // The above copyright notice and this permission notice shall be
21 | // included in all copies or substantial portions of the Software.
22 | //
23 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 |
31 | package com.codebutler.android_websockets;
32 |
33 | import android.util.Log;
34 |
35 | import java.io.*;
36 | import java.util.Arrays;
37 | import java.util.List;
38 |
39 | public class HybiParser {
40 | private static final String TAG = "HybiParser";
41 |
42 | private WebSocketClient mClient;
43 |
44 | private boolean mMasking = true;
45 |
46 | private int mStage;
47 |
48 | private boolean mFinal;
49 | private boolean mMasked;
50 | private int mOpcode;
51 | private int mLengthSize;
52 | private int mLength;
53 | private int mMode;
54 |
55 | private byte[] mMask = new byte[0];
56 | private byte[] mPayload = new byte[0];
57 |
58 | private boolean mClosed = false;
59 |
60 | private ByteArrayOutputStream mBuffer = new ByteArrayOutputStream();
61 |
62 | private static final int BYTE = 255;
63 | private static final int FIN = 128;
64 | private static final int MASK = 128;
65 | private static final int RSV1 = 64;
66 | private static final int RSV2 = 32;
67 | private static final int RSV3 = 16;
68 | private static final int OPCODE = 15;
69 | private static final int LENGTH = 127;
70 |
71 | private static final int MODE_TEXT = 1;
72 | private static final int MODE_BINARY = 2;
73 |
74 | private static final int OP_CONTINUATION = 0;
75 | private static final int OP_TEXT = 1;
76 | private static final int OP_BINARY = 2;
77 | private static final int OP_CLOSE = 8;
78 | private static final int OP_PING = 9;
79 | private static final int OP_PONG = 10;
80 |
81 | private static final List OPCODES = Arrays.asList(
82 | OP_CONTINUATION,
83 | OP_TEXT,
84 | OP_BINARY,
85 | OP_CLOSE,
86 | OP_PING,
87 | OP_PONG
88 | );
89 |
90 | private static final List FRAGMENTED_OPCODES = Arrays.asList(
91 | OP_CONTINUATION, OP_TEXT, OP_BINARY
92 | );
93 |
94 | public HybiParser(WebSocketClient client) {
95 | mClient = client;
96 | }
97 |
98 | private static byte[] mask(byte[] payload, byte[] mask, int offset) {
99 | if (mask.length == 0) return payload;
100 |
101 | for (int i = 0; i < payload.length - offset; i++) {
102 | payload[offset + i] = (byte) (payload[offset + i] ^ mask[i % 4]);
103 | }
104 | return payload;
105 | }
106 |
107 | public void start(HappyDataInputStream stream) throws IOException {
108 | while (true) {
109 | if (stream.available() == -1) break;
110 | switch (mStage) {
111 | case 0:
112 | parseOpcode(stream.readByte());
113 | break;
114 | case 1:
115 | parseLength(stream.readByte());
116 | break;
117 | case 2:
118 | parseExtendedLength(stream.readBytes(mLengthSize));
119 | break;
120 | case 3:
121 | mMask = stream.readBytes(4);
122 | mStage = 4;
123 | break;
124 | case 4:
125 | mPayload = stream.readBytes(mLength);
126 | emitFrame();
127 | mStage = 0;
128 | break;
129 | }
130 | }
131 | mClient.getListener().onDisconnect(0, "EOF");
132 | }
133 |
134 | private void parseOpcode(byte data) throws ProtocolError {
135 | boolean rsv1 = (data & RSV1) == RSV1;
136 | boolean rsv2 = (data & RSV2) == RSV2;
137 | boolean rsv3 = (data & RSV3) == RSV3;
138 |
139 | if (rsv1 || rsv2 || rsv3) {
140 | throw new ProtocolError("RSV not zero");
141 | }
142 |
143 | mFinal = (data & FIN) == FIN;
144 | mOpcode = (data & OPCODE);
145 | mMask = new byte[0];
146 | mPayload = new byte[0];
147 |
148 | if (!OPCODES.contains(mOpcode)) {
149 | throw new ProtocolError("Bad opcode");
150 | }
151 |
152 | if (!FRAGMENTED_OPCODES.contains(mOpcode) && !mFinal) {
153 | throw new ProtocolError("Expected non-final packet");
154 | }
155 |
156 | mStage = 1;
157 | }
158 |
159 | private void parseLength(byte data) {
160 | mMasked = (data & MASK) == MASK;
161 | mLength = (data & LENGTH);
162 |
163 | if (mLength >= 0 && mLength <= 125) {
164 | mStage = mMasked ? 3 : 4;
165 | } else {
166 | mLengthSize = (mLength == 126) ? 2 : 8;
167 | mStage = 2;
168 | }
169 | }
170 |
171 | private void parseExtendedLength(byte[] buffer) throws ProtocolError {
172 | mLength = getInteger(buffer);
173 | mStage = mMasked ? 3 : 4;
174 | }
175 |
176 | public byte[] frame(String data) {
177 | return frame(data, OP_TEXT, -1);
178 | }
179 |
180 | public byte[] frame(byte[] data) {
181 | return frame(data, OP_BINARY, -1);
182 | }
183 |
184 | private byte[] frame(byte[] data, int opcode, int errorCode) {
185 | return frame((Object)data, opcode, errorCode);
186 | }
187 |
188 | private byte[] frame(String data, int opcode, int errorCode) {
189 | return frame((Object)data, opcode, errorCode);
190 | }
191 |
192 | private byte[] frame(Object data, int opcode, int errorCode) {
193 | if (mClosed) return null;
194 |
195 | Log.d(TAG, "Creating frame for: " + data + " op: " + opcode + " err: " + errorCode);
196 |
197 | byte[] buffer = (data instanceof String) ? decode((String) data) : (byte[]) data;
198 | int insert = (errorCode > 0) ? 2 : 0;
199 | int length = buffer.length + insert;
200 | int header = (length <= 125) ? 2 : (length <= 65535 ? 4 : 10);
201 | int offset = header + (mMasking ? 4 : 0);
202 | int masked = mMasking ? MASK : 0;
203 | byte[] frame = new byte[length + offset];
204 |
205 | frame[0] = (byte) ((byte)FIN | (byte)opcode);
206 |
207 | if (length <= 125) {
208 | frame[1] = (byte) (masked | length);
209 | } else if (length <= 65535) {
210 | frame[1] = (byte) (masked | 126);
211 | frame[2] = (byte) Math.floor(length / 256);
212 | frame[3] = (byte) (length & BYTE);
213 | } else {
214 | frame[1] = (byte) (masked | 127);
215 | frame[2] = (byte) (((int) Math.floor(length / Math.pow(2, 56))) & BYTE);
216 | frame[3] = (byte) (((int) Math.floor(length / Math.pow(2, 48))) & BYTE);
217 | frame[4] = (byte) (((int) Math.floor(length / Math.pow(2, 40))) & BYTE);
218 | frame[5] = (byte) (((int) Math.floor(length / Math.pow(2, 32))) & BYTE);
219 | frame[6] = (byte) (((int) Math.floor(length / Math.pow(2, 24))) & BYTE);
220 | frame[7] = (byte) (((int) Math.floor(length / Math.pow(2, 16))) & BYTE);
221 | frame[8] = (byte) (((int) Math.floor(length / Math.pow(2, 8))) & BYTE);
222 | frame[9] = (byte) (length & BYTE);
223 | }
224 |
225 | if (errorCode > 0) {
226 | frame[offset] = (byte) (((int) Math.floor(errorCode / 256)) & BYTE);
227 | frame[offset+1] = (byte) (errorCode & BYTE);
228 | }
229 | System.arraycopy(buffer, 0, frame, offset + insert, buffer.length);
230 |
231 | if (mMasking) {
232 | byte[] mask = {
233 | (byte) Math.floor(Math.random() * 256), (byte) Math.floor(Math.random() * 256),
234 | (byte) Math.floor(Math.random() * 256), (byte) Math.floor(Math.random() * 256)
235 | };
236 | System.arraycopy(mask, 0, frame, header, mask.length);
237 | mask(frame, mask, offset);
238 | }
239 |
240 | return frame;
241 | }
242 |
243 | public void ping(String message) {
244 | mClient.send(frame(message, OP_PING, -1));
245 | }
246 |
247 | public void close(int code, String reason) {
248 | if (mClosed) return;
249 | mClient.send(frame(reason, OP_CLOSE, code));
250 | mClosed = true;
251 | }
252 |
253 | private void emitFrame() throws IOException {
254 | byte[] payload = mask(mPayload, mMask, 0);
255 | int opcode = mOpcode;
256 |
257 | if (opcode == OP_CONTINUATION) {
258 | if (mMode == 0) {
259 | throw new ProtocolError("Mode was not set.");
260 | }
261 | mBuffer.write(payload);
262 | if (mFinal) {
263 | byte[] message = mBuffer.toByteArray();
264 | if (mMode == MODE_TEXT) {
265 | mClient.getListener().onMessage(encode(message));
266 | } else {
267 | mClient.getListener().onMessage(message);
268 | }
269 | reset();
270 | }
271 |
272 | } else if (opcode == OP_TEXT) {
273 | if (mFinal) {
274 | String messageText = encode(payload);
275 | mClient.getListener().onMessage(messageText);
276 | } else {
277 | mMode = MODE_TEXT;
278 | mBuffer.write(payload);
279 | }
280 |
281 | } else if (opcode == OP_BINARY) {
282 | if (mFinal) {
283 | mClient.getListener().onMessage(payload);
284 | } else {
285 | mMode = MODE_BINARY;
286 | mBuffer.write(payload);
287 | }
288 |
289 | } else if (opcode == OP_CLOSE) {
290 | int code = (payload.length >= 2) ? 256 * payload[0] + payload[1] : 0;
291 | String reason = (payload.length > 2) ? encode(slice(payload, 2)) : null;
292 | Log.d(TAG, "Got close op! " + code + " " + reason);
293 | mClient.getListener().onDisconnect(code, reason);
294 |
295 | } else if (opcode == OP_PING) {
296 | if (payload.length > 125) { throw new ProtocolError("Ping payload too large"); }
297 | Log.d(TAG, "Sending pong!!");
298 | mClient.sendFrame(frame(payload, OP_PONG, -1));
299 |
300 | } else if (opcode == OP_PONG) {
301 | String message = encode(payload);
302 | // FIXME: Fire callback...
303 | Log.d(TAG, "Got pong! " + message);
304 | }
305 | }
306 |
307 | private void reset() {
308 | mMode = 0;
309 | mBuffer.reset();
310 | }
311 |
312 | private String encode(byte[] buffer) {
313 | try {
314 | return new String(buffer, "UTF-8");
315 | } catch (UnsupportedEncodingException e) {
316 | throw new RuntimeException(e);
317 | }
318 | }
319 |
320 | private byte[] decode(String string) {
321 | try {
322 | return (string).getBytes("UTF-8");
323 | } catch (UnsupportedEncodingException e) {
324 | throw new RuntimeException(e);
325 | }
326 | }
327 |
328 | private int getInteger(byte[] bytes) throws ProtocolError {
329 | long i = byteArrayToLong(bytes, 0, bytes.length);
330 | if (i < 0 || i > Integer.MAX_VALUE) {
331 | throw new ProtocolError("Bad integer: " + i);
332 | }
333 | return (int) i;
334 | }
335 |
336 | private byte[] slice(byte[] array, int start) {
337 | return Arrays.copyOfRange(array, start, array.length);
338 | }
339 |
340 | public static class ProtocolError extends IOException {
341 | public ProtocolError(String detailMessage) {
342 | super(detailMessage);
343 | }
344 | }
345 |
346 | private static long byteArrayToLong(byte[] b, int offset, int length) {
347 | if (b.length < length)
348 | throw new IllegalArgumentException("length must be less than or equal to b.length");
349 |
350 | long value = 0;
351 | for (int i = 0; i < length; i++) {
352 | int shift = (length - 1 - i) * 8;
353 | value += (b[i + offset] & 0x000000FF) << shift;
354 | }
355 | return value;
356 | }
357 |
358 | public static class HappyDataInputStream extends DataInputStream {
359 | public HappyDataInputStream(InputStream in) {
360 | super(in);
361 | }
362 |
363 | public byte[] readBytes(int length) throws IOException {
364 | byte[] buffer = new byte[length];
365 | readFully(buffer);
366 | return buffer;
367 | }
368 | }
369 | }
--------------------------------------------------------------------------------
/android-app/src/com/codebutler/android_websockets/WebSocketClient.java:
--------------------------------------------------------------------------------
1 | package com.codebutler.android_websockets;
2 |
3 | import android.os.Handler;
4 | import android.os.HandlerThread;
5 | import android.text.TextUtils;
6 | import android.util.Base64;
7 | import android.util.Log;
8 | import org.apache.http.*;
9 | import org.apache.http.client.HttpResponseException;
10 | import org.apache.http.message.BasicLineParser;
11 | import org.apache.http.message.BasicNameValuePair;
12 |
13 | import javax.net.SocketFactory;
14 | import javax.net.ssl.SSLContext;
15 | import javax.net.ssl.SSLException;
16 | import javax.net.ssl.SSLSocketFactory;
17 | import javax.net.ssl.TrustManager;
18 | import java.io.EOFException;
19 | import java.io.IOException;
20 | import java.io.OutputStream;
21 | import java.io.PrintWriter;
22 | import java.net.Socket;
23 | import java.net.URI;
24 | import java.security.KeyManagementException;
25 | import java.security.MessageDigest;
26 | import java.security.NoSuchAlgorithmException;
27 | import java.util.List;
28 |
29 | public class WebSocketClient {
30 | private static final String TAG = "WebSocketClient";
31 |
32 | private URI mURI;
33 | private Listener mListener;
34 | private Socket mSocket;
35 | private Thread mThread;
36 | private HandlerThread mHandlerThread;
37 | private Handler mHandler;
38 | private List mExtraHeaders;
39 | private HybiParser mParser;
40 |
41 | private final Object mSendLock = new Object();
42 |
43 | private static TrustManager[] sTrustManagers;
44 |
45 | public static void setTrustManagers(TrustManager[] tm) {
46 | sTrustManagers = tm;
47 | }
48 |
49 | public WebSocketClient(URI uri, Listener listener, List extraHeaders) {
50 | mURI = uri;
51 | mListener = listener;
52 | mExtraHeaders = extraHeaders;
53 | mParser = new HybiParser(this);
54 |
55 | mHandlerThread = new HandlerThread("websocket-thread");
56 | mHandlerThread.start();
57 | mHandler = new Handler(mHandlerThread.getLooper());
58 | }
59 |
60 | public Listener getListener() {
61 | return mListener;
62 | }
63 |
64 | public void connect() {
65 | if (mThread != null && mThread.isAlive()) {
66 | return;
67 | }
68 |
69 | mThread = new Thread(new Runnable() {
70 | @Override
71 | public void run() {
72 | try {
73 | String secret = createSecret();
74 |
75 | int port = (mURI.getPort() != -1) ? mURI.getPort() : (mURI.getScheme().equals("wss") ? 443 : 80);
76 |
77 | String path = TextUtils.isEmpty(mURI.getPath()) ? "/" : mURI.getPath();
78 | if (!TextUtils.isEmpty(mURI.getQuery())) {
79 | path += "?" + mURI.getQuery();
80 | }
81 |
82 | String originScheme = mURI.getScheme().equals("wss") ? "https" : "http";
83 | URI origin = new URI(originScheme, "//" + mURI.getHost(), null);
84 |
85 | SocketFactory factory = mURI.getScheme().equals("wss") ? getSSLSocketFactory() : SocketFactory.getDefault();
86 | mSocket = factory.createSocket(mURI.getHost(), port);
87 |
88 | PrintWriter out = new PrintWriter(mSocket.getOutputStream());
89 | out.print("GET " + path + " HTTP/1.1\r\n");
90 | out.print("Upgrade: websocket\r\n");
91 | out.print("Connection: Upgrade\r\n");
92 | out.print("Host: " + mURI.getHost() + "\r\n");
93 | out.print("Origin: " + origin.toString() + "\r\n");
94 | out.print("Sec-WebSocket-Key: " + secret + "\r\n");
95 | out.print("Sec-WebSocket-Version: 13\r\n");
96 | if (mExtraHeaders != null) {
97 | for (NameValuePair pair : mExtraHeaders) {
98 | out.print(String.format("%s: %s\r\n", pair.getName(), pair.getValue()));
99 | }
100 | }
101 | out.print("\r\n");
102 | out.flush();
103 |
104 | HybiParser.HappyDataInputStream stream = new HybiParser.HappyDataInputStream(mSocket.getInputStream());
105 |
106 | // Read HTTP response status line.
107 | StatusLine statusLine = parseStatusLine(readLine(stream));
108 | if (statusLine == null) {
109 | throw new HttpException("Received no reply from server.");
110 | } else if (statusLine.getStatusCode() != HttpStatus.SC_SWITCHING_PROTOCOLS) {
111 | throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase());
112 | }
113 |
114 | // Read HTTP response headers.
115 | String line;
116 | boolean validated = false;
117 |
118 | while (!TextUtils.isEmpty(line = readLine(stream))) {
119 | Header header = parseHeader(line);
120 | if (header.getName().equals("Sec-WebSocket-Accept")) {
121 | String expected = createSecretValidation(secret);
122 | String actual = header.getValue().trim();
123 |
124 | if (!expected.equals(actual)) {
125 | throw new HttpException("Bad Sec-WebSocket-Accept header value.");
126 | }
127 |
128 | validated = true;
129 | }
130 | }
131 |
132 | if (!validated) {
133 | throw new HttpException("No Sec-WebSocket-Accept header.");
134 | }
135 |
136 | mListener.onConnect();
137 |
138 | // Now decode websocket frames.
139 | mParser.start(stream);
140 |
141 | } catch (EOFException ex) {
142 | Log.d(TAG, "WebSocket EOF!", ex);
143 | mListener.onDisconnect(0, "EOF");
144 |
145 | } catch (SSLException ex) {
146 | // Connection reset by peer
147 | Log.d(TAG, "Websocket SSL error!", ex);
148 | mListener.onDisconnect(0, "SSL");
149 |
150 | } catch (Exception ex) {
151 | mListener.onError(ex);
152 | }
153 | }
154 | });
155 | mThread.start();
156 | }
157 |
158 | public void disconnect() {
159 | if (mSocket != null) {
160 | mHandler.post(new Runnable() {
161 | @Override
162 | public void run() {
163 | try {
164 | mSocket.close();
165 | mSocket = null;
166 | } catch (IOException ex) {
167 | Log.d(TAG, "Error while disconnecting", ex);
168 | mListener.onError(ex);
169 | }
170 | }
171 | });
172 | }
173 | }
174 |
175 | public void send(String data) {
176 | sendFrame(mParser.frame(data));
177 | }
178 |
179 | public void send(byte[] data) {
180 | sendFrame(mParser.frame(data));
181 | }
182 |
183 | private StatusLine parseStatusLine(String line) {
184 | if (TextUtils.isEmpty(line)) {
185 | return null;
186 | }
187 | return BasicLineParser.parseStatusLine(line, new BasicLineParser());
188 | }
189 |
190 | private Header parseHeader(String line) {
191 | return BasicLineParser.parseHeader(line, new BasicLineParser());
192 | }
193 |
194 | // Can't use BufferedReader because it buffers past the HTTP data.
195 | private String readLine(HybiParser.HappyDataInputStream reader) throws IOException {
196 | int readChar = reader.read();
197 | if (readChar == -1) {
198 | return null;
199 | }
200 | StringBuilder string = new StringBuilder("");
201 | while (readChar != '\n') {
202 | if (readChar != '\r') {
203 | string.append((char) readChar);
204 | }
205 |
206 | readChar = reader.read();
207 | if (readChar == -1) {
208 | return null;
209 | }
210 | }
211 | return string.toString();
212 | }
213 |
214 | private String createSecret() {
215 | byte[] nonce = new byte[16];
216 | for (int i = 0; i < 16; i++) {
217 | nonce[i] = (byte) (Math.random() * 256);
218 | }
219 | return Base64.encodeToString(nonce, Base64.DEFAULT).trim();
220 | }
221 |
222 | private String createSecretValidation(String secret) {
223 | try {
224 | MessageDigest md = MessageDigest.getInstance("SHA-1");
225 | md.update((secret + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").getBytes());
226 | return Base64.encodeToString(md.digest(), Base64.DEFAULT).trim();
227 | } catch (NoSuchAlgorithmException e) {
228 | throw new RuntimeException(e);
229 | }
230 | }
231 |
232 | void sendFrame(final byte[] frame) {
233 | mHandler.post(new Runnable() {
234 | @Override
235 | public void run() {
236 | try {
237 | synchronized (mSendLock) {
238 | if (mSocket == null) {
239 | throw new IllegalStateException("Socket not connected");
240 | }
241 | OutputStream outputStream = mSocket.getOutputStream();
242 | outputStream.write(frame);
243 | outputStream.flush();
244 | }
245 | } catch (IOException e) {
246 | mListener.onError(e);
247 | }
248 | }
249 | });
250 | }
251 |
252 | public interface Listener {
253 | public void onConnect();
254 | public void onMessage(String message);
255 | public void onMessage(byte[] data);
256 | public void onDisconnect(int code, String reason);
257 | public void onError(Exception error);
258 | }
259 |
260 | private SSLSocketFactory getSSLSocketFactory() throws NoSuchAlgorithmException, KeyManagementException {
261 | SSLContext context = SSLContext.getInstance("TLS");
262 | context.init(null, sTrustManagers, null);
263 | return context.getSocketFactory();
264 | }
265 | }
266 |
--------------------------------------------------------------------------------
/android-app/src/nl/meta/mobile/chat/MobileChatActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | Mobile Chat (ff-mobile-chat) is a cross platform
3 | (Android, iOS, Windows Phone 8, web) chat supported by NodeJS websockets.
4 |
5 |
6 | Copyright (C) 2013-2014 Terry Wahl & Marco Jacobs
7 |
8 | This program is free software: you can redistribute it and/or modify
9 | it under the terms of the GNU Affero General Public License as
10 | published by the Free Software Foundation, either version 3 of the
11 | License, or (at your option) any later version.
12 |
13 | This program is distributed in the hope that it will be useful,
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | GNU Affero General Public License for more details.
17 |
18 | You should have received a copy of the GNU Affero General Public License
19 | along with this program. If not, see .
20 | */
21 |
22 | package nl.meta.mobile.chat;
23 |
24 | import java.net.URI;
25 | import java.util.Arrays;
26 | import java.util.List;
27 |
28 | import org.apache.http.message.BasicNameValuePair;
29 |
30 | import android.app.Activity;
31 | import android.os.Bundle;
32 | import android.os.Handler;
33 | import android.view.View;
34 | import android.view.View.OnClickListener;
35 | import android.widget.Button;
36 | import android.widget.EditText;
37 | import android.widget.LinearLayout;
38 | import android.widget.ScrollView;
39 | import android.widget.TextView;
40 |
41 | import com.codebutler.android_websockets.WebSocketClient;
42 |
43 | public class MobileChatActivity extends Activity {
44 |
45 | // Fields
46 | private TextView tvConnectStatus;
47 | private EditText etName, etMessage;
48 | private ScrollView svMessages;
49 | private LinearLayout llMessages;
50 | private Button btnSend;
51 |
52 | // This library requires a raw websocket url.
53 | // For NodeJS with SockJS this should be
54 | // "ws://YOUR.URL:PORT/IDENTIFIER/websocket"
55 | private final String CONSTANT_WEBSOCKETS_URL = "ws://your.site.nl:6975/mobilechat/websocket";
56 | private final String CONSTANT_NO_NAME_ERROR_MSG = "Please put you name in box above!";
57 |
58 | private WebSocketClient mClient;
59 | private boolean connected = false;
60 | private Handler mHandler;
61 |
62 | @Override
63 | protected void onCreate(Bundle savedInstanceState) {
64 | super.onCreate(savedInstanceState);
65 | setContentView(R.layout.activity_mobile_chat);
66 |
67 | // Declares
68 | tvConnectStatus = (TextView) findViewById(R.id.tvConnected);
69 | etName = (EditText) findViewById(R.id.etName);
70 | llMessages = (LinearLayout) findViewById(R.id.llMessages);
71 | svMessages = (ScrollView) findViewById(R.id.svMessages);
72 | etMessage = (EditText) findViewById(R.id.etMessage);
73 | btnSend = (Button) findViewById(R.id.btnSend);
74 |
75 | mHandler = new Handler();
76 |
77 | // Update connection label
78 | setConnectionLabel();
79 |
80 | // Send message button handler
81 | btnSend.setOnClickListener(new OnClickListener() {
82 | @Override
83 | public void onClick(View v) {
84 | // check connection
85 | if (connected) {
86 | // check name not null
87 | if (!etName.getText().toString().equals("")) {
88 | if (!etMessage.getText().toString().equals("")) {
89 | // Send message
90 | mClient.send(etName.getText().toString() + ": " + etMessage.getText().toString());
91 | etMessage.setText("");
92 | }
93 | } else {
94 | // Name is empty
95 | addMessageToChat(CONSTANT_NO_NAME_ERROR_MSG);
96 | }
97 | }
98 | }
99 | });
100 |
101 | // Websockets setup
102 | List extraHeaders = Arrays.asList(new BasicNameValuePair("Cookie", "session=abcd"));
103 | mClient = new WebSocketClient(URI.create(CONSTANT_WEBSOCKETS_URL), new WebSocketClient.Listener() {
104 |
105 | @Override
106 | public void onMessage(byte[] data) {
107 | // Byte array not used
108 | System.out.println(data);
109 | }
110 |
111 | @Override
112 | public void onMessage(String message) {
113 | // Process message - Handler required because it's on the UI
114 | // thread.
115 | final String messageForHandler = message;
116 | mHandler.post(new Runnable() {
117 | @Override
118 | public void run() {
119 | addMessageToChat(messageForHandler);
120 | }
121 | });
122 | }
123 |
124 | @Override
125 | public void onError(Exception error) {
126 | // Should handle these errors...
127 | error.getStackTrace();
128 | Thread.currentThread().getStackTrace();
129 | }
130 |
131 | @Override
132 | public void onDisconnect(int code, String reason) {
133 | connected = false;
134 | // This is already on a handler
135 | mHandler.post(new Runnable() {
136 | @Override
137 | public void run() {
138 | setConnectionLabel();
139 | }
140 | });
141 |
142 | }
143 |
144 | @Override
145 | public void onConnect() {
146 | connected = true;
147 | // This is already on a handler
148 | mHandler.post(new Runnable() {
149 | @Override
150 | public void run() {
151 | setConnectionLabel();
152 | }
153 | });
154 | }
155 | }, extraHeaders);
156 |
157 | // Tell the client to connect
158 | mClient.connect();
159 | }
160 |
161 | /**
162 | * Depending on the connection status this method will set the
163 | * tvConnectStatus
164 | */
165 | private void setConnectionLabel() {
166 | if (connected) {
167 | tvConnectStatus.setText("Connected!");
168 | tvConnectStatus.setTextColor(getResources().getColor(R.color.light_green));
169 | } else {
170 | tvConnectStatus.setText("Disconnected.");
171 | tvConnectStatus.setTextColor(getResources().getColor(R.color.red));
172 | }
173 | }
174 |
175 | /**
176 | * This method adds a new TextView with the message to the chatbox.
177 | *
178 | * @param message
179 | * The message to be added.
180 | */
181 | private void addMessageToChat(String message) {
182 | TextView tv = new TextView(this);
183 | tv.setText(message);
184 | llMessages.addView(tv);
185 | // Scroll to the end
186 | svMessages.fullScroll(View.FOCUS_DOWN);
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/Mobile Chat.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | F5E36BF01851FB140014401D /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F5E36BEF1851FB140014401D /* UIKit.framework */; };
11 | F5E36BF21851FB140014401D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F5E36BF11851FB140014401D /* Foundation.framework */; };
12 | F5E36BF41851FB140014401D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F5E36BF31851FB140014401D /* CoreGraphics.framework */; };
13 | F5E36BFA1851FB140014401D /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = F5E36BF81851FB140014401D /* InfoPlist.strings */; };
14 | F5E36BFC1851FB140014401D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F5E36BFB1851FB140014401D /* main.m */; };
15 | F5E36C001851FB140014401D /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F5E36BFF1851FB140014401D /* AppDelegate.m */; };
16 | F5E36C021851FB140014401D /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = F5E36C011851FB140014401D /* Default.png */; };
17 | F5E36C041851FB140014401D /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F5E36C031851FB140014401D /* Default@2x.png */; };
18 | F5E36C061851FB140014401D /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F5E36C051851FB140014401D /* Default-568h@2x.png */; };
19 | F5E36C091851FB140014401D /* MainStoryboard_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F5E36C071851FB140014401D /* MainStoryboard_iPhone.storyboard */; };
20 | F5E36C0C1851FB140014401D /* MainStoryboard_iPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F5E36C0A1851FB140014401D /* MainStoryboard_iPad.storyboard */; };
21 | F5E36C0F1851FB140014401D /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F5E36C0E1851FB140014401D /* ViewController.m */; };
22 | F5E36C601851FB260014401D /* .gitignore in Resources */ = {isa = PBXBuildFile; fileRef = F5E36C161851FB250014401D /* .gitignore */; };
23 | F5E36C611851FB260014401D /* .gitmodules in Resources */ = {isa = PBXBuildFile; fileRef = F5E36C171851FB250014401D /* .gitmodules */; };
24 | F5E36C641851FB260014401D /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = F5E36C1C1851FB250014401D /* LICENSE */; };
25 | F5E36C661851FB260014401D /* README.rst in Resources */ = {isa = PBXBuildFile; fileRef = F5E36C1F1851FB250014401D /* README.rst */; };
26 | F5E36C671851FB260014401D /* base64.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E36C211851FB250014401D /* base64.c */; };
27 | F5E36C681851FB260014401D /* NSData+SRB64Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = F5E36C241851FB250014401D /* NSData+SRB64Additions.m */; };
28 | F5E36C691851FB260014401D /* SRWebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = F5E36C271851FB250014401D /* SRWebSocket.m */; };
29 | F5E36C941851FB6F0014401D /* libicucore.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F5E36C931851FB6F0014401D /* libicucore.dylib */; };
30 | F5E36C961851FB790014401D /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F5E36C951851FB790014401D /* CFNetwork.framework */; };
31 | F5E36C981851FB810014401D /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F5E36C971851FB810014401D /* Security.framework */; };
32 | /* End PBXBuildFile section */
33 |
34 | /* Begin PBXContainerItemProxy section */
35 | F5E36C8B1851FB260014401D /* PBXContainerItemProxy */ = {
36 | isa = PBXContainerItemProxy;
37 | containerPortal = F5E36C2D1851FB260014401D /* SocketRocket.xcodeproj */;
38 | proxyType = 2;
39 | remoteGlobalIDString = F6B2082D1450F597009315AF;
40 | remoteInfo = SocketRocket;
41 | };
42 | F5E36C8D1851FB260014401D /* PBXContainerItemProxy */ = {
43 | isa = PBXContainerItemProxy;
44 | containerPortal = F5E36C2D1851FB260014401D /* SocketRocket.xcodeproj */;
45 | proxyType = 2;
46 | remoteGlobalIDString = F668C880153E91210044DBAC;
47 | remoteInfo = SocketRocketOSX;
48 | };
49 | F5E36C8F1851FB260014401D /* PBXContainerItemProxy */ = {
50 | isa = PBXContainerItemProxy;
51 | containerPortal = F5E36C2D1851FB260014401D /* SocketRocket.xcodeproj */;
52 | proxyType = 2;
53 | remoteGlobalIDString = F6BDA802145900D200FE3253;
54 | remoteInfo = SRWebSocketTests;
55 | };
56 | F5E36C911851FB260014401D /* PBXContainerItemProxy */ = {
57 | isa = PBXContainerItemProxy;
58 | containerPortal = F5E36C2D1851FB260014401D /* SocketRocket.xcodeproj */;
59 | proxyType = 2;
60 | remoteGlobalIDString = F62417E314D52F3C003CE997;
61 | remoteInfo = TestChat;
62 | };
63 | /* End PBXContainerItemProxy section */
64 |
65 | /* Begin PBXFileReference section */
66 | F5E36BEC1851FB140014401D /* Mobile Chat.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Mobile Chat.app"; sourceTree = BUILT_PRODUCTS_DIR; };
67 | F5E36BEF1851FB140014401D /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
68 | F5E36BF11851FB140014401D /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
69 | F5E36BF31851FB140014401D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
70 | F5E36BF71851FB140014401D /* Mobile Chat-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Mobile Chat-Info.plist"; sourceTree = ""; };
71 | F5E36BF91851FB140014401D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
72 | F5E36BFB1851FB140014401D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
73 | F5E36BFD1851FB140014401D /* Mobile Chat-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Mobile Chat-Prefix.pch"; sourceTree = ""; };
74 | F5E36BFE1851FB140014401D /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
75 | F5E36BFF1851FB140014401D /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
76 | F5E36C011851FB140014401D /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; };
77 | F5E36C031851FB140014401D /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; };
78 | F5E36C051851FB140014401D /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; };
79 | F5E36C081851FB140014401D /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard_iPhone.storyboard; sourceTree = ""; };
80 | F5E36C0B1851FB140014401D /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard_iPad.storyboard; sourceTree = ""; };
81 | F5E36C0D1851FB140014401D /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; };
82 | F5E36C0E1851FB140014401D /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; };
83 | F5E36C161851FB250014401D /* .gitignore */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = .gitignore; sourceTree = ""; };
84 | F5E36C171851FB250014401D /* .gitmodules */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = .gitmodules; sourceTree = ""; };
85 | F5E36C1C1851FB250014401D /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = ""; };
86 | F5E36C1F1851FB250014401D /* README.rst */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.rst; sourceTree = ""; };
87 | F5E36C211851FB250014401D /* base64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = base64.c; sourceTree = ""; };
88 | F5E36C221851FB250014401D /* base64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = base64.h; sourceTree = ""; };
89 | F5E36C231851FB250014401D /* NSData+SRB64Additions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+SRB64Additions.h"; sourceTree = ""; };
90 | F5E36C241851FB250014401D /* NSData+SRB64Additions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+SRB64Additions.m"; sourceTree = ""; };
91 | F5E36C251851FB250014401D /* SocketRocket-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SocketRocket-Prefix.pch"; sourceTree = ""; };
92 | F5E36C261851FB250014401D /* SRWebSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SRWebSocket.h; sourceTree = ""; };
93 | F5E36C271851FB250014401D /* SRWebSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SRWebSocket.m; sourceTree = ""; };
94 | F5E36C2D1851FB260014401D /* SocketRocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = SocketRocket.xcodeproj; sourceTree = ""; };
95 | F5E36C931851FB6F0014401D /* libicucore.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libicucore.dylib; path = usr/lib/libicucore.dylib; sourceTree = SDKROOT; };
96 | F5E36C951851FB790014401D /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; };
97 | F5E36C971851FB810014401D /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
98 | F5E36C99185209090014401D /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; };
99 | /* End PBXFileReference section */
100 |
101 | /* Begin PBXFrameworksBuildPhase section */
102 | F5E36BE91851FB140014401D /* Frameworks */ = {
103 | isa = PBXFrameworksBuildPhase;
104 | buildActionMask = 2147483647;
105 | files = (
106 | F5E36BF21851FB140014401D /* Foundation.framework in Frameworks */,
107 | F5E36C981851FB810014401D /* Security.framework in Frameworks */,
108 | F5E36C961851FB790014401D /* CFNetwork.framework in Frameworks */,
109 | F5E36C941851FB6F0014401D /* libicucore.dylib in Frameworks */,
110 | F5E36BF01851FB140014401D /* UIKit.framework in Frameworks */,
111 | F5E36BF41851FB140014401D /* CoreGraphics.framework in Frameworks */,
112 | );
113 | runOnlyForDeploymentPostprocessing = 0;
114 | };
115 | /* End PBXFrameworksBuildPhase section */
116 |
117 | /* Begin PBXGroup section */
118 | F5E36BE31851FB140014401D = {
119 | isa = PBXGroup;
120 | children = (
121 | F5E36C99185209090014401D /* AssetsLibrary.framework */,
122 | F5E36C151851FB250014401D /* SocketRocket-master */,
123 | F5E36BF51851FB140014401D /* Mobile Chat */,
124 | F5E36BEE1851FB140014401D /* Frameworks */,
125 | F5E36BED1851FB140014401D /* Products */,
126 | );
127 | sourceTree = "";
128 | };
129 | F5E36BED1851FB140014401D /* Products */ = {
130 | isa = PBXGroup;
131 | children = (
132 | F5E36BEC1851FB140014401D /* Mobile Chat.app */,
133 | );
134 | name = Products;
135 | sourceTree = "";
136 | };
137 | F5E36BEE1851FB140014401D /* Frameworks */ = {
138 | isa = PBXGroup;
139 | children = (
140 | F5E36C931851FB6F0014401D /* libicucore.dylib */,
141 | F5E36C951851FB790014401D /* CFNetwork.framework */,
142 | F5E36C971851FB810014401D /* Security.framework */,
143 | F5E36BEF1851FB140014401D /* UIKit.framework */,
144 | F5E36BF11851FB140014401D /* Foundation.framework */,
145 | F5E36BF31851FB140014401D /* CoreGraphics.framework */,
146 | );
147 | name = Frameworks;
148 | sourceTree = "";
149 | };
150 | F5E36BF51851FB140014401D /* Mobile Chat */ = {
151 | isa = PBXGroup;
152 | children = (
153 | F5E36BFE1851FB140014401D /* AppDelegate.h */,
154 | F5E36BFF1851FB140014401D /* AppDelegate.m */,
155 | F5E36C071851FB140014401D /* MainStoryboard_iPhone.storyboard */,
156 | F5E36C0A1851FB140014401D /* MainStoryboard_iPad.storyboard */,
157 | F5E36C0D1851FB140014401D /* ViewController.h */,
158 | F5E36C0E1851FB140014401D /* ViewController.m */,
159 | F5E36BF61851FB140014401D /* Supporting Files */,
160 | );
161 | path = "Mobile Chat";
162 | sourceTree = "";
163 | };
164 | F5E36BF61851FB140014401D /* Supporting Files */ = {
165 | isa = PBXGroup;
166 | children = (
167 | F5E36BF71851FB140014401D /* Mobile Chat-Info.plist */,
168 | F5E36BF81851FB140014401D /* InfoPlist.strings */,
169 | F5E36BFB1851FB140014401D /* main.m */,
170 | F5E36BFD1851FB140014401D /* Mobile Chat-Prefix.pch */,
171 | F5E36C011851FB140014401D /* Default.png */,
172 | F5E36C031851FB140014401D /* Default@2x.png */,
173 | F5E36C051851FB140014401D /* Default-568h@2x.png */,
174 | );
175 | name = "Supporting Files";
176 | sourceTree = "";
177 | };
178 | F5E36C151851FB250014401D /* SocketRocket-master */ = {
179 | isa = PBXGroup;
180 | children = (
181 | F5E36C161851FB250014401D /* .gitignore */,
182 | F5E36C171851FB250014401D /* .gitmodules */,
183 | F5E36C1C1851FB250014401D /* LICENSE */,
184 | F5E36C1F1851FB250014401D /* README.rst */,
185 | F5E36C201851FB250014401D /* SocketRocket */,
186 | F5E36C2D1851FB260014401D /* SocketRocket.xcodeproj */,
187 | );
188 | path = "SocketRocket-master";
189 | sourceTree = "";
190 | };
191 | F5E36C201851FB250014401D /* SocketRocket */ = {
192 | isa = PBXGroup;
193 | children = (
194 | F5E36C211851FB250014401D /* base64.c */,
195 | F5E36C221851FB250014401D /* base64.h */,
196 | F5E36C231851FB250014401D /* NSData+SRB64Additions.h */,
197 | F5E36C241851FB250014401D /* NSData+SRB64Additions.m */,
198 | F5E36C251851FB250014401D /* SocketRocket-Prefix.pch */,
199 | F5E36C261851FB250014401D /* SRWebSocket.h */,
200 | F5E36C271851FB250014401D /* SRWebSocket.m */,
201 | );
202 | path = SocketRocket;
203 | sourceTree = "";
204 | };
205 | F5E36C2E1851FB260014401D /* Products */ = {
206 | isa = PBXGroup;
207 | children = (
208 | F5E36C8C1851FB260014401D /* libSocketRocket.a */,
209 | F5E36C8E1851FB260014401D /* SocketRocket.framework */,
210 | F5E36C901851FB260014401D /* SRWebSocketTests.octest */,
211 | F5E36C921851FB260014401D /* TestChat.app */,
212 | );
213 | name = Products;
214 | sourceTree = "";
215 | };
216 | /* End PBXGroup section */
217 |
218 | /* Begin PBXNativeTarget section */
219 | F5E36BEB1851FB140014401D /* Mobile Chat */ = {
220 | isa = PBXNativeTarget;
221 | buildConfigurationList = F5E36C121851FB140014401D /* Build configuration list for PBXNativeTarget "Mobile Chat" */;
222 | buildPhases = (
223 | F5E36BE81851FB140014401D /* Sources */,
224 | F5E36BE91851FB140014401D /* Frameworks */,
225 | F5E36BEA1851FB140014401D /* Resources */,
226 | );
227 | buildRules = (
228 | );
229 | dependencies = (
230 | );
231 | name = "Mobile Chat";
232 | productName = "Mobile Chat";
233 | productReference = F5E36BEC1851FB140014401D /* Mobile Chat.app */;
234 | productType = "com.apple.product-type.application";
235 | };
236 | /* End PBXNativeTarget section */
237 |
238 | /* Begin PBXProject section */
239 | F5E36BE41851FB140014401D /* Project object */ = {
240 | isa = PBXProject;
241 | attributes = {
242 | LastUpgradeCheck = 0460;
243 | ORGANIZATIONNAME = FHICT;
244 | };
245 | buildConfigurationList = F5E36BE71851FB140014401D /* Build configuration list for PBXProject "Mobile Chat" */;
246 | compatibilityVersion = "Xcode 3.2";
247 | developmentRegion = English;
248 | hasScannedForEncodings = 0;
249 | knownRegions = (
250 | en,
251 | );
252 | mainGroup = F5E36BE31851FB140014401D;
253 | productRefGroup = F5E36BED1851FB140014401D /* Products */;
254 | projectDirPath = "";
255 | projectReferences = (
256 | {
257 | ProductGroup = F5E36C2E1851FB260014401D /* Products */;
258 | ProjectRef = F5E36C2D1851FB260014401D /* SocketRocket.xcodeproj */;
259 | },
260 | );
261 | projectRoot = "";
262 | targets = (
263 | F5E36BEB1851FB140014401D /* Mobile Chat */,
264 | );
265 | };
266 | /* End PBXProject section */
267 |
268 | /* Begin PBXReferenceProxy section */
269 | F5E36C8C1851FB260014401D /* libSocketRocket.a */ = {
270 | isa = PBXReferenceProxy;
271 | fileType = archive.ar;
272 | path = libSocketRocket.a;
273 | remoteRef = F5E36C8B1851FB260014401D /* PBXContainerItemProxy */;
274 | sourceTree = BUILT_PRODUCTS_DIR;
275 | };
276 | F5E36C8E1851FB260014401D /* SocketRocket.framework */ = {
277 | isa = PBXReferenceProxy;
278 | fileType = wrapper.framework;
279 | path = SocketRocket.framework;
280 | remoteRef = F5E36C8D1851FB260014401D /* PBXContainerItemProxy */;
281 | sourceTree = BUILT_PRODUCTS_DIR;
282 | };
283 | F5E36C901851FB260014401D /* SRWebSocketTests.octest */ = {
284 | isa = PBXReferenceProxy;
285 | fileType = wrapper.cfbundle;
286 | path = SRWebSocketTests.octest;
287 | remoteRef = F5E36C8F1851FB260014401D /* PBXContainerItemProxy */;
288 | sourceTree = BUILT_PRODUCTS_DIR;
289 | };
290 | F5E36C921851FB260014401D /* TestChat.app */ = {
291 | isa = PBXReferenceProxy;
292 | fileType = wrapper.application;
293 | path = TestChat.app;
294 | remoteRef = F5E36C911851FB260014401D /* PBXContainerItemProxy */;
295 | sourceTree = BUILT_PRODUCTS_DIR;
296 | };
297 | /* End PBXReferenceProxy section */
298 |
299 | /* Begin PBXResourcesBuildPhase section */
300 | F5E36BEA1851FB140014401D /* Resources */ = {
301 | isa = PBXResourcesBuildPhase;
302 | buildActionMask = 2147483647;
303 | files = (
304 | F5E36BFA1851FB140014401D /* InfoPlist.strings in Resources */,
305 | F5E36C021851FB140014401D /* Default.png in Resources */,
306 | F5E36C041851FB140014401D /* Default@2x.png in Resources */,
307 | F5E36C061851FB140014401D /* Default-568h@2x.png in Resources */,
308 | F5E36C091851FB140014401D /* MainStoryboard_iPhone.storyboard in Resources */,
309 | F5E36C0C1851FB140014401D /* MainStoryboard_iPad.storyboard in Resources */,
310 | F5E36C601851FB260014401D /* .gitignore in Resources */,
311 | F5E36C611851FB260014401D /* .gitmodules in Resources */,
312 | F5E36C641851FB260014401D /* LICENSE in Resources */,
313 | F5E36C661851FB260014401D /* README.rst in Resources */,
314 | );
315 | runOnlyForDeploymentPostprocessing = 0;
316 | };
317 | /* End PBXResourcesBuildPhase section */
318 |
319 | /* Begin PBXSourcesBuildPhase section */
320 | F5E36BE81851FB140014401D /* Sources */ = {
321 | isa = PBXSourcesBuildPhase;
322 | buildActionMask = 2147483647;
323 | files = (
324 | F5E36BFC1851FB140014401D /* main.m in Sources */,
325 | F5E36C001851FB140014401D /* AppDelegate.m in Sources */,
326 | F5E36C0F1851FB140014401D /* ViewController.m in Sources */,
327 | F5E36C671851FB260014401D /* base64.c in Sources */,
328 | F5E36C681851FB260014401D /* NSData+SRB64Additions.m in Sources */,
329 | F5E36C691851FB260014401D /* SRWebSocket.m in Sources */,
330 | );
331 | runOnlyForDeploymentPostprocessing = 0;
332 | };
333 | /* End PBXSourcesBuildPhase section */
334 |
335 | /* Begin PBXVariantGroup section */
336 | F5E36BF81851FB140014401D /* InfoPlist.strings */ = {
337 | isa = PBXVariantGroup;
338 | children = (
339 | F5E36BF91851FB140014401D /* en */,
340 | );
341 | name = InfoPlist.strings;
342 | sourceTree = "";
343 | };
344 | F5E36C071851FB140014401D /* MainStoryboard_iPhone.storyboard */ = {
345 | isa = PBXVariantGroup;
346 | children = (
347 | F5E36C081851FB140014401D /* en */,
348 | );
349 | name = MainStoryboard_iPhone.storyboard;
350 | sourceTree = "";
351 | };
352 | F5E36C0A1851FB140014401D /* MainStoryboard_iPad.storyboard */ = {
353 | isa = PBXVariantGroup;
354 | children = (
355 | F5E36C0B1851FB140014401D /* en */,
356 | );
357 | name = MainStoryboard_iPad.storyboard;
358 | sourceTree = "";
359 | };
360 | /* End PBXVariantGroup section */
361 |
362 | /* Begin XCBuildConfiguration section */
363 | F5E36C101851FB140014401D /* Debug */ = {
364 | isa = XCBuildConfiguration;
365 | buildSettings = {
366 | ALWAYS_SEARCH_USER_PATHS = NO;
367 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
368 | CLANG_CXX_LIBRARY = "libc++";
369 | CLANG_ENABLE_OBJC_ARC = YES;
370 | CLANG_WARN_CONSTANT_CONVERSION = YES;
371 | CLANG_WARN_EMPTY_BODY = YES;
372 | CLANG_WARN_ENUM_CONVERSION = YES;
373 | CLANG_WARN_INT_CONVERSION = YES;
374 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
375 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
376 | COPY_PHASE_STRIP = NO;
377 | GCC_C_LANGUAGE_STANDARD = gnu99;
378 | GCC_DYNAMIC_NO_PIC = NO;
379 | GCC_OPTIMIZATION_LEVEL = 0;
380 | GCC_PREPROCESSOR_DEFINITIONS = (
381 | "DEBUG=1",
382 | "$(inherited)",
383 | );
384 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
385 | GCC_WARN_ABOUT_RETURN_TYPE = YES;
386 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
387 | GCC_WARN_UNUSED_VARIABLE = YES;
388 | IPHONEOS_DEPLOYMENT_TARGET = 6.1;
389 | ONLY_ACTIVE_ARCH = YES;
390 | SDKROOT = iphoneos;
391 | TARGETED_DEVICE_FAMILY = "1,2";
392 | };
393 | name = Debug;
394 | };
395 | F5E36C111851FB140014401D /* Release */ = {
396 | isa = XCBuildConfiguration;
397 | buildSettings = {
398 | ALWAYS_SEARCH_USER_PATHS = NO;
399 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
400 | CLANG_CXX_LIBRARY = "libc++";
401 | CLANG_ENABLE_OBJC_ARC = YES;
402 | CLANG_WARN_CONSTANT_CONVERSION = YES;
403 | CLANG_WARN_EMPTY_BODY = YES;
404 | CLANG_WARN_ENUM_CONVERSION = YES;
405 | CLANG_WARN_INT_CONVERSION = YES;
406 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
407 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
408 | COPY_PHASE_STRIP = YES;
409 | GCC_C_LANGUAGE_STANDARD = gnu99;
410 | GCC_WARN_ABOUT_RETURN_TYPE = YES;
411 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
412 | GCC_WARN_UNUSED_VARIABLE = YES;
413 | IPHONEOS_DEPLOYMENT_TARGET = 6.1;
414 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
415 | SDKROOT = iphoneos;
416 | TARGETED_DEVICE_FAMILY = "1,2";
417 | VALIDATE_PRODUCT = YES;
418 | };
419 | name = Release;
420 | };
421 | F5E36C131851FB140014401D /* Debug */ = {
422 | isa = XCBuildConfiguration;
423 | buildSettings = {
424 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
425 | GCC_PREFIX_HEADER = "Mobile Chat/Mobile Chat-Prefix.pch";
426 | INFOPLIST_FILE = "Mobile Chat/Mobile Chat-Info.plist";
427 | PRODUCT_NAME = "$(TARGET_NAME)";
428 | TARGETED_DEVICE_FAMILY = "1,2";
429 | WRAPPER_EXTENSION = app;
430 | };
431 | name = Debug;
432 | };
433 | F5E36C141851FB140014401D /* Release */ = {
434 | isa = XCBuildConfiguration;
435 | buildSettings = {
436 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
437 | GCC_PREFIX_HEADER = "Mobile Chat/Mobile Chat-Prefix.pch";
438 | INFOPLIST_FILE = "Mobile Chat/Mobile Chat-Info.plist";
439 | PRODUCT_NAME = "$(TARGET_NAME)";
440 | TARGETED_DEVICE_FAMILY = "1,2";
441 | WRAPPER_EXTENSION = app;
442 | };
443 | name = Release;
444 | };
445 | /* End XCBuildConfiguration section */
446 |
447 | /* Begin XCConfigurationList section */
448 | F5E36BE71851FB140014401D /* Build configuration list for PBXProject "Mobile Chat" */ = {
449 | isa = XCConfigurationList;
450 | buildConfigurations = (
451 | F5E36C101851FB140014401D /* Debug */,
452 | F5E36C111851FB140014401D /* Release */,
453 | );
454 | defaultConfigurationIsVisible = 0;
455 | defaultConfigurationName = Release;
456 | };
457 | F5E36C121851FB140014401D /* Build configuration list for PBXNativeTarget "Mobile Chat" */ = {
458 | isa = XCConfigurationList;
459 | buildConfigurations = (
460 | F5E36C131851FB140014401D /* Debug */,
461 | F5E36C141851FB140014401D /* Release */,
462 | );
463 | defaultConfigurationIsVisible = 0;
464 | defaultConfigurationName = Release;
465 | };
466 | /* End XCConfigurationList section */
467 | };
468 | rootObject = F5E36BE41851FB140014401D /* Project object */;
469 | }
470 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/Mobile Chat.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/Mobile Chat/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // Mobile Chat
4 | /*
5 | Mobile Chat (ff-mobile-chat) is a cross platform
6 | (Android, iOS, Windows Phone 8, web) chat supported by NodeJS websockets.
7 |
8 |
9 | Copyright (C) 2013-2014 Terry Wahl & Marco Jacobs
10 |
11 | This program is free software: you can redistribute it and/or modify
12 | it under the terms of the GNU Affero General Public License as
13 | published by the Free Software Foundation, either version 3 of the
14 | License, or (at your option) any later version.
15 |
16 | This program is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU Affero General Public License for more details.
20 |
21 | You should have received a copy of the GNU Affero General Public License
22 | along with this program. If not, see .
23 | */
24 |
25 | #import
26 |
27 | @interface AppDelegate : UIResponder
28 |
29 | @property (strong, nonatomic) UIWindow *window;
30 |
31 | @end
32 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/Mobile Chat/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // Mobile Chat
4 | /*
5 | Mobile Chat (ff-mobile-chat) is a cross platform
6 | (Android, iOS, Windows Phone 8, web) chat supported by NodeJS websockets.
7 |
8 |
9 | Copyright (C) 2013-2014 Terry Wahl & Marco Jacobs
10 |
11 | This program is free software: you can redistribute it and/or modify
12 | it under the terms of the GNU Affero General Public License as
13 | published by the Free Software Foundation, either version 3 of the
14 | License, or (at your option) any later version.
15 |
16 | This program is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU Affero General Public License for more details.
20 |
21 | You should have received a copy of the GNU Affero General Public License
22 | along with this program. If not, see .
23 | */
24 |
25 | #import "AppDelegate.h"
26 |
27 | @implementation AppDelegate
28 |
29 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
30 | {
31 | // Override point for customization after application launch.
32 | return YES;
33 | }
34 |
35 | - (void)applicationWillResignActive:(UIApplication *)application
36 | {
37 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
38 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
39 | }
40 |
41 | - (void)applicationDidEnterBackground:(UIApplication *)application
42 | {
43 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
44 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
45 | }
46 |
47 | - (void)applicationWillEnterForeground:(UIApplication *)application
48 | {
49 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
50 | }
51 |
52 | - (void)applicationDidBecomeActive:(UIApplication *)application
53 | {
54 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
55 | }
56 |
57 | - (void)applicationWillTerminate:(UIApplication *)application
58 | {
59 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
60 | }
61 |
62 | @end
63 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/Mobile Chat/Default-568h@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TerryWahl/Mobile-Multiplatform-Websockets-Android-iOS-Windows-Phone-Web/10d3a2dc8947166040671affe8ec79e73ebca6f8/ios-app/Mobile Chat/Mobile Chat/Default-568h@2x.png
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/Mobile Chat/Default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TerryWahl/Mobile-Multiplatform-Websockets-Android-iOS-Windows-Phone-Web/10d3a2dc8947166040671affe8ec79e73ebca6f8/ios-app/Mobile Chat/Mobile Chat/Default.png
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/Mobile Chat/Default@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TerryWahl/Mobile-Multiplatform-Websockets-Android-iOS-Windows-Phone-Web/10d3a2dc8947166040671affe8ec79e73ebca6f8/ios-app/Mobile Chat/Mobile Chat/Default@2x.png
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/Mobile Chat/Mobile Chat-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | ${PRODUCT_NAME}
9 | CFBundleExecutable
10 | ${EXECUTABLE_NAME}
11 | CFBundleIdentifier
12 | nl.meta.${PRODUCT_NAME:rfc1034identifier}
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | ${PRODUCT_NAME}
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1.0
25 | LSRequiresIPhoneOS
26 |
27 | UIMainStoryboardFile
28 | MainStoryboard_iPhone
29 | UIMainStoryboardFile~ipad
30 | MainStoryboard_iPad
31 | UIRequiredDeviceCapabilities
32 |
33 | armv7
34 |
35 | UISupportedInterfaceOrientations
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationLandscapeLeft
39 | UIInterfaceOrientationLandscapeRight
40 |
41 | UISupportedInterfaceOrientations~ipad
42 |
43 | UIInterfaceOrientationPortrait
44 | UIInterfaceOrientationPortraitUpsideDown
45 | UIInterfaceOrientationLandscapeLeft
46 | UIInterfaceOrientationLandscapeRight
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/Mobile Chat/Mobile Chat-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2012 Square Inc.
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | #ifdef __OBJC__
18 | #import
19 | #endif
20 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/Mobile Chat/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // Mobile Chat
4 | /*
5 | Mobile Chat (ff-mobile-chat) is a cross platform
6 | (Android, iOS, Windows Phone 8, web) chat supported by NodeJS websockets.
7 |
8 |
9 | Copyright (C) 2013-2014 Terry Wahl & Marco Jacobs
10 |
11 | This program is free software: you can redistribute it and/or modify
12 | it under the terms of the GNU Affero General Public License as
13 | published by the Free Software Foundation, either version 3 of the
14 | License, or (at your option) any later version.
15 |
16 | This program is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU Affero General Public License for more details.
20 |
21 | You should have received a copy of the GNU Affero General Public License
22 | along with this program. If not, see .
23 | */
24 |
25 | #import
26 | #import "SRWebSocket.h"
27 |
28 | @interface ViewController : UIViewController
29 | @property (weak, nonatomic) IBOutlet UILabel *tvStatus;
30 | @property (weak, nonatomic) IBOutlet UITextView *tfOutput;
31 | @property (weak, nonatomic) IBOutlet UITextField *tfInput;
32 | @property (weak, nonatomic) IBOutlet UITextField *tfName;
33 |
34 |
35 | - (IBAction)btnSend:(id)sender;
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/Mobile Chat/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // Mobile Chat
4 | /*
5 | Mobile Chat (ff-mobile-chat) is a cross platform
6 | (Android, iOS, Windows Phone 8, web) chat supported by NodeJS websockets.
7 |
8 |
9 | Copyright (C) 2013-2014 Terry Wahl & Marco Jacobs
10 |
11 | This program is free software: you can redistribute it and/or modify
12 | it under the terms of the GNU Affero General Public License as
13 | published by the Free Software Foundation, either version 3 of the
14 | License, or (at your option) any later version.
15 |
16 | This program is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU Affero General Public License for more details.
20 |
21 | You should have received a copy of the GNU Affero General Public License
22 | along with this program. If not, see .
23 | */
24 |
25 | #import "ViewController.h"
26 |
27 | @interface ViewController ()
28 |
29 | @property (nonatomic, readwrite) SRWebSocket *sockjsSocket;
30 | @property (nonatomic, readwrite) BOOL socketReady;
31 |
32 | @end
33 |
34 | @implementation ViewController
35 |
36 | @synthesize tvStatus;
37 | @synthesize tfOutput;
38 | @synthesize tfInput, tfName;
39 |
40 | -(void)viewWillAppear:(BOOL)animated
41 | {
42 | //Startup websockets
43 | self.socketReady = NO;
44 | //This library requires a raw websocket url. It does accept http instead of ws.
45 | //For NodeJS with SockJS this should be "http://YOUR.URL:PORT/IDENTIFIER/websocket"
46 | self.sockjsSocket = [[SRWebSocket alloc] initWithURL:[[NSURL alloc] initWithString:@"http://your.site:6975/mobilechat/websocket"]];
47 | self.sockjsSocket.delegate = self;
48 | [self.sockjsSocket open];
49 |
50 | }
51 |
52 | - (void)viewDidLoad
53 | {
54 | [super viewDidLoad];
55 | //add delegates to remove keyboard on pressing enter
56 | self.tfInput.delegate = self;
57 | self.tfName.delegate = self;
58 | // Do any additional setup after loading the view, typically from a nib.
59 | }
60 |
61 | - (void)didReceiveMemoryWarning
62 | {
63 | [super didReceiveMemoryWarning];
64 | // Dispose of any resources that can be recreated.
65 | }
66 |
67 | - (IBAction)btnSend:(id)sender {
68 | //Check if name field is not empty
69 | if([tfName.text isEqualToString:@""]){
70 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Name missing" message:@"Fill in a name to chat"
71 | delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
72 | [alert show];
73 | }
74 | //check if message field is not empty
75 | else if([tfInput.text isEqualToString:@""]){
76 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Message missing" message:@"Message can't be empty"
77 | delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
78 | [alert show];
79 | }
80 | //Everything is ok, send the message!
81 | else{
82 | if(self.socketReady){
83 | NSString *input = [tfInput text];
84 | tfInput.text = @"";
85 |
86 | NSString *addName = [NSString stringWithFormat:@"%@%@", tfName.text, @": "];
87 | NSString *combined = [NSString stringWithFormat:@"%@%@", addName, input];
88 |
89 | [self.sockjsSocket send:combined];
90 | }
91 | }
92 | }
93 |
94 | // SRWebSocket handlers
95 | - (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message
96 | {
97 | NSString *output = [tfOutput text];
98 |
99 | //Set the textview on bottom focus when it becomes scrollable
100 | if([tfOutput.text hasSuffix:@"\n"])
101 | {
102 | if (tfOutput.contentSize.height - tfOutput.bounds.size.height > -30)
103 | {
104 | double delayInSeconds = 0.2;
105 | dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
106 | dispatch_after(popTime, dispatch_get_main_queue(), ^(void)
107 | {
108 | CGPoint bottomOffset = CGPointMake(0, tfOutput.contentSize.height - tfOutput.bounds.size.height);
109 | [tfOutput setContentOffset:bottomOffset animated:YES];
110 | });
111 | }
112 | }
113 |
114 | //Combine old messages with new messages
115 | NSString *combined = [NSString stringWithFormat:@"%@%@", message, @"\n"];
116 | NSString *newOutput = [NSString stringWithFormat:@"%@%@", output, combined];
117 |
118 | tfOutput.text = newOutput;
119 |
120 | }
121 |
122 | - (BOOL)textFieldShouldReturn:(UITextField *)textField {
123 | [textField resignFirstResponder];
124 | return NO;
125 | }
126 |
127 | - (void) viewWillDisappear:(BOOL)animated
128 | {
129 | [self.sockjsSocket close];
130 | self.sockjsSocket = nil;
131 | }
132 |
133 | - (void)webSocketDidOpen:(SRWebSocket *)webSocket
134 | {
135 | self.socketReady = YES;
136 | tvStatus.text = @"Online";
137 | }
138 |
139 | - (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean
140 | {
141 | self.socketReady = NO;
142 | tvStatus.text = @"Offline";
143 | }
144 | @end
145 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/Mobile Chat/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 | /*
3 | Mobile Chat (ff-mobile-chat) is a cross platform
4 | (Android, iOS, Windows Phone 8, web) chat supported by NodeJS websockets.
5 |
6 |
7 | Copyright (C) 2013-2014 Terry Wahl & Marco Jacobs
8 |
9 | This program is free software: you can redistribute it and/or modify
10 | it under the terms of the GNU Affero General Public License as
11 | published by the Free Software Foundation, either version 3 of the
12 | License, or (at your option) any later version.
13 |
14 | This program is distributed in the hope that it will be useful,
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | GNU Affero General Public License for more details.
18 |
19 | You should have received a copy of the GNU Affero General Public License
20 | along with this program. If not, see .
21 | */
22 |
23 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/Mobile Chat/en.lproj/MainStoryboard_iPad.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/Mobile Chat/en.lproj/MainStoryboard_iPhone.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
23 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/Mobile Chat/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // Mobile Chat
4 | /*
5 | Mobile Chat (ff-mobile-chat) is a cross platform
6 | (Android, iOS, Windows Phone 8, web) chat supported by NodeJS websockets.
7 |
8 |
9 | Copyright (C) 2013-2014 Terry Wahl & Marco Jacobs
10 |
11 | This program is free software: you can redistribute it and/or modify
12 | it under the terms of the GNU Affero General Public License as
13 | published by the Free Software Foundation, either version 3 of the
14 | License, or (at your option) any later version.
15 |
16 | This program is distributed in the hope that it will be useful,
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 | GNU Affero General Public License for more details.
20 |
21 | You should have received a copy of the GNU Affero General Public License
22 | along with this program. If not, see .
23 | */
24 |
25 | #import
26 |
27 | #import "AppDelegate.h"
28 |
29 | int main(int argc, char *argv[])
30 | {
31 | @autoreleasepool {
32 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/SocketRocket-master/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | .env/
3 | *.egg-info
4 | reports/
5 | build/
6 | nohup.out
7 | .DS_Store
8 | xcuserdata/
9 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/SocketRocket-master/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "pages"]
2 | path = pages
3 | url = git://github.com/square/SocketRocket.git
4 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/SocketRocket-master/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Copyright 2012 Square Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 |
16 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/SocketRocket-master/README.rst:
--------------------------------------------------------------------------------
1 | SocketRocket Objective-C WebSocket Client (beta)
2 | ================================================
3 | A conforming WebSocket (`RFC 6455 `_)
4 | client library.
5 |
6 | `Test results for SocketRocket here `_.
7 | You can compare to what `modern browsers look like here
8 | `_.
9 |
10 | SocketRocket currently conforms to all ~300 of `Autobahn
11 | `_'s fuzzing tests (aside from
12 | two UTF-8 ones where it is merely *non-strict*. tests 6.4.2 and 6.4.4)
13 |
14 | Features/Design
15 | ---------------
16 | - TLS (wss) support. It uses CFStream so we get this for *free*
17 | - Uses NSStream/CFNetworking. Earlier implementations used ``dispatch_io``,
18 | however, this proved to be make TLS nearly impossible. Also I wanted this to
19 | work in iOS 4.x. (SocketRocket only supports 5.0 and above now)
20 | - Uses ARC. It uses the 4.0 compatible subset (no weak refs).
21 | - Seems to perform quite well
22 | - Parallel architecture. Most of the work is done in background worker queues.
23 | - Delegate-based. Had older versions that could use blocks too, but I felt it
24 | didn't blend well with retain cycles and just objective C in general.
25 |
26 | Changes
27 | -------
28 |
29 | v0.3.1-beta2 - 2013-01-12
30 | `````````````````````````
31 |
32 | - Stability fix for ``closeWithCode:reason:`` (Thanks @michaelpetrov!)
33 | - Actually clean up the NSStreams and remove them from their runloops
34 | - ``_SRRunLoopThread``'s ``main`` wasn't correctly wrapped with
35 | ``@autoreleasepool``
36 |
37 | v0.3.1-beta1 - 2013-01-12
38 | `````````````````````````
39 |
40 | - Cleaned up GCD so OS_OBJECT_USE_OBJC_RETAIN_RELEASE is optional
41 | - Removed deprecated ``dispatch_get_current_queue`` in favor of ``dispatch_queue_set_specific`` and ``dispatch_get_specific``
42 | - Dropping support for iOS 4.0 (it may still work)
43 |
44 |
45 | Installing (iOS)
46 | ----------------
47 | There's a few options. Choose one, or just figure it out
48 |
49 | - You can copy all the files in the SocketRocket group into your app.
50 | - Include SocketRocket as a subproject and use libSocketRocket
51 |
52 | If you do this, you must add -ObjC to your "other linker flags" option
53 |
54 | - For OS X you will have to repackage make a .framework target. I will take
55 | contributions. Message me if you are interested.
56 |
57 |
58 | Depending on how you configure your project you may need to ``#import`` either
59 | ```` or ``"SRSocketRocket.h"``
60 |
61 | Framework Dependencies
62 | ``````````````````````
63 | Your .app must be linked against the following frameworks/dylibs
64 |
65 | - libicucore.dylib
66 | - CFNetwork.framework
67 | - Security.framework
68 | - Foundation.framework
69 |
70 | Installing (OS X)
71 | -----------------
72 | SocketRocket now has (64-bit only) OS X support. ``SocketRocket.framework``
73 | inside Xcode project is for OS X only. It should be identical in function aside
74 | from the unicode validation. ICU isn't shipped with OS X which is what the
75 | original implementation used for unicode validation. The workaround is much
76 | more rhudimentary and less robust.
77 |
78 | 1. Add SocketRocket.xcodeproj as either a subproject of your app or in your workspace.
79 | 2. Add ``SocketRocket.framework`` to the link libraries
80 | 3. If you don't have a "copy files" step for ``Framework``, create one
81 | 4. Add ``SocketRocket.framework`` to the "copy files" step.
82 |
83 | API
84 | ---
85 | The classes
86 |
87 | ``SRWebSocket``
88 | ```````````````
89 | The Web Socket.
90 |
91 | .. note:: ``SRWebSocket`` will retain itself between ``-(void)open`` and when it
92 | closes, errors, or fails. This is similar to how ``NSURLConnection`` behaves.
93 | (unlike ``NSURLConnection``, ``SRWebSocket`` won't retain the delegate)
94 |
95 | What you need to know
96 |
97 | .. code-block:: objective-c
98 |
99 | @interface SRWebSocket : NSObject
100 |
101 | // Make it with this
102 | - (id)initWithURLRequest:(NSURLRequest *)request;
103 |
104 | // Set this before opening
105 | @property (nonatomic, assign) id delegate;
106 |
107 | - (void)open;
108 |
109 | // Close it with this
110 | - (void)close;
111 |
112 | // Send a UTF8 String or Data
113 | - (void)send:(id)data;
114 |
115 | @end
116 |
117 | ``SRWebSocketDelegate``
118 | ```````````````````````
119 | You implement this
120 |
121 | .. code-block:: objective-c
122 |
123 | @protocol SRWebSocketDelegate
124 |
125 | - (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message;
126 |
127 | @optional
128 |
129 | - (void)webSocketDidOpen:(SRWebSocket *)webSocket;
130 | - (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error;
131 | - (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean;
132 |
133 | @end
134 |
135 | Known Issues/Server Todo's
136 | --------------------------
137 | - Needs auth delegates (like in NSURLConnection)
138 | - Move the streams off the main runloop (most of the work is backgrounded uses
139 | GCD, but I just haven't gotten around to moving it off the main loop since I
140 | converted it from dispatch_io)
141 | - Re-implement server. I removed an existing implementation as well because it
142 | wasn't being used and I wasn't super happy with the interface. Will revisit
143 | this.
144 | - Separate framer and client logic. This will make it nicer when having a
145 | server.
146 |
147 | Testing
148 | -------
149 | Included are setup scripts for the python testing environment. It comes
150 | packaged with vitualenv so all the dependencies are installed in userland.
151 |
152 | To run the short test from the command line, run::
153 |
154 | make test
155 |
156 | To run all the tests, run::
157 |
158 | make test_all
159 |
160 | The short tests don't include the performance tests. (the test harness is
161 | actually the bottleneck, not SocketRocket).
162 |
163 | The first time this is run, it may take a while to install the dependencies. It
164 | will be smooth sailing after that. After the test runs the makefile will open
165 | the results page in your browser. If nothing comes up, you failed. Working on
166 | making this interface a bit nicer.
167 |
168 | To run from the app, choose the ``SocketRocket`` target and run the test action
169 | (``cmd+u``). It runs the same thing, but makes it easier to debug. There is
170 | some serious pre/post hooks in the Test action. You can edit it to customize
171 | behavior.
172 |
173 | .. note:: Xcode only up to version 4.4 is currently supported for the test
174 | harness
175 |
176 | TestChat Demo Application
177 | -------------------------
178 | SocketRocket includes a demo app, TestChat. It will "chat" with a listening
179 | websocket on port 9900.
180 |
181 | It's a simple project. Uses storyboard. Storyboard is sweet.
182 |
183 |
184 | TestChat Server
185 | ```````````````
186 | We've included a small server for the chat app. It has a simple function.
187 | It will take a message and broadcast it to all other connected clients.
188 |
189 | We have to get some dependencies. We also want to reuse the virtualenv we made
190 | when we ran the tests. If you haven't run the tests yet, go into the
191 | SocketRocket root directory and type::
192 |
193 | make test
194 |
195 | This will set up your `virtualenv `_.
196 | Now, in your terminal::
197 |
198 | source .env/bin/activate
199 | pip install git+https://github.com/facebook/tornado.git
200 |
201 | In the same terminal session, start the chatroom server::
202 |
203 | python TestChatServer/py/chatroom.py
204 |
205 | There's also a Go implementation (with the latest weekly) where you can::
206 |
207 | cd TestChatServer/go
208 | go run chatroom.go
209 |
210 | Chatting
211 | ````````
212 | Now, start TestChat.app (just run the target in the XCode project). If you had
213 | it started already you can hit the refresh button to reconnect. It should say
214 | "Connected!" on top.
215 |
216 | To talk with the app, open up your browser to `http://localhost:9000 `_ and
217 | start chatting.
218 |
219 |
220 | WebSocket Server Implementation Recommendations
221 | -----------------------------------------------
222 | SocketRocket has been used with the following libraries:
223 |
224 | - `Tornado `_
225 | - Go's `weekly build `_ (the official release has an
226 | outdated protocol, so you may have to use weekly until `Go 1
227 | `_ is released)
228 | - `Autobahn `_ (using its fuzzing
229 | client)
230 |
231 | The Tornado one is dirt simple and works like a charm. (`IPython notebook
232 | `_ uses it
233 | too). It's much easier to configure handlers and routes than in
234 | Autobahn/twisted.
235 |
236 | As far as Go's goes, it works in my limited testing. I much prefer go's
237 | concurrency model as well. Try it! You may like it.
238 | It could use some more control over things such as pings, etc., but I
239 | am sure it will come in time.
240 |
241 | Autobahn is a great test suite. The Python server code is good, and conforms
242 | well (obviously). Hovever, for me, twisted would be a deal-breaker for writing
243 | something new. I find it a bit too complex and heavy for a simple service. If
244 | you are already using twisted though, Autobahn is probably for you.
245 |
246 | Contributing
247 | ------------
248 | Any contributors to the master SocketRocket repository must sign the `Individual
249 | Contributor License Agreement
250 | (CLA)
251 | `_.
252 | It's a short form that covers our bases and makes sure you're eligible to
253 | contribute.
254 |
255 | When you have a change you'd like to see in the master repository, `send a pull
256 | request `_. Before we merge your
257 | request, we'll make sure you're in the list of people who have signed a CLA.
258 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/SocketRocket-master/SocketRocket.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/SocketRocket-master/SocketRocket.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/SocketRocket-master/SocketRocket.xcodeproj/xcshareddata/xcschemes/SocketRocket.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
47 |
51 |
52 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
66 |
70 |
71 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
85 |
91 |
92 |
93 |
94 |
95 |
101 |
102 |
103 |
104 |
108 |
109 |
110 |
111 |
120 |
121 |
125 |
126 |
130 |
131 |
135 |
136 |
140 |
141 |
142 |
143 |
149 |
150 |
152 |
153 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/SocketRocket-master/SocketRocket.xcodeproj/xcshareddata/xcschemes/SocketRocketOSX.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
42 |
43 |
44 |
45 |
51 |
52 |
54 |
55 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/SocketRocket-master/SocketRocket.xcodeproj/xcshareddata/xcschemes/SocketRocketTests.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
52 |
53 |
57 |
58 |
62 |
63 |
67 |
68 |
72 |
73 |
74 |
75 |
81 |
82 |
84 |
85 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/SocketRocket-master/SocketRocket.xcodeproj/xcshareddata/xcschemes/TestChat.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
51 |
52 |
58 |
59 |
60 |
61 |
65 |
66 |
70 |
71 |
75 |
76 |
80 |
81 |
82 |
83 |
89 |
90 |
96 |
97 |
98 |
99 |
101 |
102 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/SocketRocket-master/SocketRocket/NSData+SRB64Additions.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2012 Square Inc.
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | #import
18 |
19 |
20 | @interface NSData (SRB64Additions)
21 |
22 | - (NSString *)SR_stringByBase64Encoding;
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/SocketRocket-master/SocketRocket/NSData+SRB64Additions.m:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2012 Square Inc.
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | #import "NSData+SRB64Additions.h"
18 | #import "base64.h"
19 |
20 |
21 | @implementation NSData (SRB64Additions)
22 |
23 | - (NSString *)SR_stringByBase64Encoding;
24 | {
25 | size_t buffer_size = (([self length] * 3 + 2) / 2);
26 |
27 | char *buffer = (char *)malloc(buffer_size);
28 |
29 | int len = b64_ntop([self bytes], [self length], buffer, buffer_size);
30 |
31 | if (len == -1) {
32 | free(buffer);
33 | return nil;
34 | } else{
35 | return [[NSString alloc] initWithBytesNoCopy:buffer length:len encoding:NSUTF8StringEncoding freeWhenDone:YES];
36 | }
37 | }
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/SocketRocket-master/SocketRocket/SRWebSocket.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2012 Square Inc.
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | #import
18 | #import
19 |
20 | typedef enum {
21 | SR_CONNECTING = 0,
22 | SR_OPEN = 1,
23 | SR_CLOSING = 2,
24 | SR_CLOSED = 3,
25 | } SRReadyState;
26 |
27 | @class SRWebSocket;
28 |
29 | extern NSString *const SRWebSocketErrorDomain;
30 |
31 | #pragma mark - SRWebSocketDelegate
32 |
33 | @protocol SRWebSocketDelegate;
34 |
35 | #pragma mark - SRWebSocket
36 |
37 | @interface SRWebSocket : NSObject
38 |
39 | @property (nonatomic, assign) id delegate;
40 |
41 | @property (nonatomic, readonly) SRReadyState readyState;
42 | @property (nonatomic, readonly, retain) NSURL *url;
43 |
44 | // This returns the negotiated protocol.
45 | // It will be nil until after the handshake completes.
46 | @property (nonatomic, readonly, copy) NSString *protocol;
47 |
48 | // Protocols should be an array of strings that turn into Sec-WebSocket-Protocol.
49 | - (id)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray *)protocols;
50 | - (id)initWithURLRequest:(NSURLRequest *)request;
51 |
52 | // Some helper constructors.
53 | - (id)initWithURL:(NSURL *)url protocols:(NSArray *)protocols;
54 | - (id)initWithURL:(NSURL *)url;
55 |
56 | // Delegate queue will be dispatch_main_queue by default.
57 | // You cannot set both OperationQueue and dispatch_queue.
58 | - (void)setDelegateOperationQueue:(NSOperationQueue*) queue;
59 | - (void)setDelegateDispatchQueue:(dispatch_queue_t) queue;
60 |
61 | // By default, it will schedule itself on +[NSRunLoop SR_networkRunLoop] using defaultModes.
62 | - (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode;
63 | - (void)unscheduleFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode;
64 |
65 | // SRWebSockets are intended for one-time-use only. Open should be called once and only once.
66 | - (void)open;
67 |
68 | - (void)close;
69 | - (void)closeWithCode:(NSInteger)code reason:(NSString *)reason;
70 |
71 | // Send a UTF8 String or Data.
72 | - (void)send:(id)data;
73 |
74 | @end
75 |
76 | #pragma mark - SRWebSocketDelegate
77 |
78 | @protocol SRWebSocketDelegate
79 |
80 | // message will either be an NSString if the server is using text
81 | // or NSData if the server is using binary.
82 | - (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message;
83 |
84 | @optional
85 |
86 | - (void)webSocketDidOpen:(SRWebSocket *)webSocket;
87 | - (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error;
88 | - (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean;
89 |
90 | @end
91 |
92 | #pragma mark - NSURLRequest (CertificateAdditions)
93 |
94 | @interface NSURLRequest (CertificateAdditions)
95 |
96 | @property (nonatomic, retain, readonly) NSArray *SR_SSLPinnedCertificates;
97 |
98 | @end
99 |
100 | #pragma mark - NSMutableURLRequest (CertificateAdditions)
101 |
102 | @interface NSMutableURLRequest (CertificateAdditions)
103 |
104 | @property (nonatomic, retain) NSArray *SR_SSLPinnedCertificates;
105 |
106 | @end
107 |
108 | #pragma mark - NSRunLoop (SRWebSocket)
109 |
110 | @interface NSRunLoop (SRWebSocket)
111 |
112 | + (NSRunLoop *)SR_networkRunLoop;
113 |
114 | @end
115 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/SocketRocket-master/SocketRocket/SocketRocket-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2012 Square Inc.
3 | //
4 | // Licensed under the Apache License, Version 2.0 (the "License");
5 | // you may not use this file except in compliance with the License.
6 | // You may obtain a copy of the License at
7 | //
8 | // http://www.apache.org/licenses/LICENSE-2.0
9 | //
10 | // Unless required by applicable law or agreed to in writing, software
11 | // distributed under the License is distributed on an "AS IS" BASIS,
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | // See the License for the specific language governing permissions and
14 | // limitations under the License.
15 | //
16 |
17 | #ifdef __cplusplus
18 | extern "C" {
19 | #endif
20 |
21 | #ifdef __OBJC__
22 | #import
23 | #endif
24 |
25 | #ifdef __cplusplus
26 | }
27 | #endif
28 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/SocketRocket-master/SocketRocket/base64.c:
--------------------------------------------------------------------------------
1 | /* $OpenBSD: base64.c,v 1.5 2006/10/21 09:55:03 otto Exp $ */
2 |
3 | /*
4 | * Copyright (c) 1996 by Internet Software Consortium.
5 | *
6 | * Permission to use, copy, modify, and distribute this software for any
7 | * purpose with or without fee is hereby granted, provided that the above
8 | * copyright notice and this permission notice appear in all copies.
9 | *
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
11 | * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
12 | * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
13 | * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
16 | * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
17 | * SOFTWARE.
18 | */
19 |
20 | /*
21 | * Portions Copyright (c) 1995 by International Business Machines, Inc.
22 | *
23 | * International Business Machines, Inc. (hereinafter called IBM) grants
24 | * permission under its copyrights to use, copy, modify, and distribute this
25 | * Software with or without fee, provided that the above copyright notice and
26 | * all paragraphs of this notice appear in all copies, and that the name of IBM
27 | * not be used in connection with the marketing of any product incorporating
28 | * the Software or modifications thereof, without specific, written prior
29 | * permission.
30 | *
31 | * To the extent it has a right to do so, IBM grants an immunity from suit
32 | * under its patents, if any, for the use, sale or manufacture of products to
33 | * the extent that such products are used for performing Domain Name System
34 | * dynamic updates in TCP/IP networks by means of the Software. No immunity is
35 | * granted for any product per se or for any other function of any product.
36 | *
37 | * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
38 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
39 | * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
40 | * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
41 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
42 | * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
43 | */
44 |
45 | /* OPENBSD ORIGINAL: lib/libc/net/base64.c */
46 |
47 |
48 | #if (!defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP)) || (!defined(HAVE_B64_PTON) && !defined(HAVE___B64_PTON))
49 |
50 | #include
51 | #include
52 | #include
53 | #include
54 | #include
55 |
56 | #include
57 | #include
58 |
59 | #include
60 | #include
61 |
62 | #include "base64.h"
63 |
64 | static const char Base64[] =
65 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
66 | static const char Pad64 = '=';
67 |
68 | /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
69 | The following encoding technique is taken from RFC 1521 by Borenstein
70 | and Freed. It is reproduced here in a slightly edited form for
71 | convenience.
72 |
73 | A 65-character subset of US-ASCII is used, enabling 6 bits to be
74 | represented per printable character. (The extra 65th character, "=",
75 | is used to signify a special processing function.)
76 |
77 | The encoding process represents 24-bit groups of input bits as output
78 | strings of 4 encoded characters. Proceeding from left to right, a
79 | 24-bit input group is formed by concatenating 3 8-bit input groups.
80 | These 24 bits are then treated as 4 concatenated 6-bit groups, each
81 | of which is translated into a single digit in the base64 alphabet.
82 |
83 | Each 6-bit group is used as an index into an array of 64 printable
84 | characters. The character referenced by the index is placed in the
85 | output string.
86 |
87 | Table 1: The Base64 Alphabet
88 |
89 | Value Encoding Value Encoding Value Encoding Value Encoding
90 | 0 A 17 R 34 i 51 z
91 | 1 B 18 S 35 j 52 0
92 | 2 C 19 T 36 k 53 1
93 | 3 D 20 U 37 l 54 2
94 | 4 E 21 V 38 m 55 3
95 | 5 F 22 W 39 n 56 4
96 | 6 G 23 X 40 o 57 5
97 | 7 H 24 Y 41 p 58 6
98 | 8 I 25 Z 42 q 59 7
99 | 9 J 26 a 43 r 60 8
100 | 10 K 27 b 44 s 61 9
101 | 11 L 28 c 45 t 62 +
102 | 12 M 29 d 46 u 63 /
103 | 13 N 30 e 47 v
104 | 14 O 31 f 48 w (pad) =
105 | 15 P 32 g 49 x
106 | 16 Q 33 h 50 y
107 |
108 | Special processing is performed if fewer than 24 bits are available
109 | at the end of the data being encoded. A full encoding quantum is
110 | always completed at the end of a quantity. When fewer than 24 input
111 | bits are available in an input group, zero bits are added (on the
112 | right) to form an integral number of 6-bit groups. Padding at the
113 | end of the data is performed using the '=' character.
114 |
115 | Since all base64 input is an integral number of octets, only the
116 | -------------------------------------------------
117 | following cases can arise:
118 |
119 | (1) the final quantum of encoding input is an integral
120 | multiple of 24 bits; here, the final unit of encoded
121 | output will be an integral multiple of 4 characters
122 | with no "=" padding,
123 | (2) the final quantum of encoding input is exactly 8 bits;
124 | here, the final unit of encoded output will be two
125 | characters followed by two "=" padding characters, or
126 | (3) the final quantum of encoding input is exactly 16 bits;
127 | here, the final unit of encoded output will be three
128 | characters followed by one "=" padding character.
129 | */
130 |
131 | #if !defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP)
132 | int
133 | b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize)
134 | {
135 | size_t datalength = 0;
136 | u_char input[3];
137 | u_char output[4];
138 | u_int i;
139 |
140 | while (2 < srclength) {
141 | input[0] = *src++;
142 | input[1] = *src++;
143 | input[2] = *src++;
144 | srclength -= 3;
145 |
146 | output[0] = input[0] >> 2;
147 | output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
148 | output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
149 | output[3] = input[2] & 0x3f;
150 |
151 | if (datalength + 4 > targsize)
152 | return (-1);
153 | target[datalength++] = Base64[output[0]];
154 | target[datalength++] = Base64[output[1]];
155 | target[datalength++] = Base64[output[2]];
156 | target[datalength++] = Base64[output[3]];
157 | }
158 |
159 | /* Now we worry about padding. */
160 | if (0 != srclength) {
161 | /* Get what's left. */
162 | input[0] = input[1] = input[2] = '\0';
163 | for (i = 0; i < srclength; i++)
164 | input[i] = *src++;
165 |
166 | output[0] = input[0] >> 2;
167 | output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
168 | output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
169 |
170 | if (datalength + 4 > targsize)
171 | return (-1);
172 | target[datalength++] = Base64[output[0]];
173 | target[datalength++] = Base64[output[1]];
174 | if (srclength == 1)
175 | target[datalength++] = Pad64;
176 | else
177 | target[datalength++] = Base64[output[2]];
178 | target[datalength++] = Pad64;
179 | }
180 | if (datalength >= targsize)
181 | return (-1);
182 | target[datalength] = '\0'; /* Returned value doesn't count \0. */
183 | return (datalength);
184 | }
185 | #endif /* !defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP) */
186 |
187 | #if !defined(HAVE_B64_PTON) && !defined(HAVE___B64_PTON)
188 |
189 | /* skips all whitespace anywhere.
190 | converts characters, four at a time, starting at (or after)
191 | src from base - 64 numbers into three 8 bit bytes in the target area.
192 | it returns the number of data bytes stored at the target, or -1 on error.
193 | */
194 |
195 | int
196 | b64_pton(char const *src, u_char *target, size_t targsize)
197 | {
198 | u_int tarindex, state;
199 | int ch;
200 | char *pos;
201 |
202 | state = 0;
203 | tarindex = 0;
204 |
205 | while ((ch = *src++) != '\0') {
206 | if (isspace(ch)) /* Skip whitespace anywhere. */
207 | continue;
208 |
209 | if (ch == Pad64)
210 | break;
211 |
212 | pos = strchr(Base64, ch);
213 | if (pos == 0) /* A non-base64 character. */
214 | return (-1);
215 |
216 | switch (state) {
217 | case 0:
218 | if (target) {
219 | if (tarindex >= targsize)
220 | return (-1);
221 | target[tarindex] = (pos - Base64) << 2;
222 | }
223 | state = 1;
224 | break;
225 | case 1:
226 | if (target) {
227 | if (tarindex + 1 >= targsize)
228 | return (-1);
229 | target[tarindex] |= (pos - Base64) >> 4;
230 | target[tarindex+1] = ((pos - Base64) & 0x0f)
231 | << 4 ;
232 | }
233 | tarindex++;
234 | state = 2;
235 | break;
236 | case 2:
237 | if (target) {
238 | if (tarindex + 1 >= targsize)
239 | return (-1);
240 | target[tarindex] |= (pos - Base64) >> 2;
241 | target[tarindex+1] = ((pos - Base64) & 0x03)
242 | << 6;
243 | }
244 | tarindex++;
245 | state = 3;
246 | break;
247 | case 3:
248 | if (target) {
249 | if (tarindex >= targsize)
250 | return (-1);
251 | target[tarindex] |= (pos - Base64);
252 | }
253 | tarindex++;
254 | state = 0;
255 | break;
256 | }
257 | }
258 |
259 | /*
260 | * We are done decoding Base-64 chars. Let's see if we ended
261 | * on a byte boundary, and/or with erroneous trailing characters.
262 | */
263 |
264 | if (ch == Pad64) { /* We got a pad char. */
265 | ch = *src++; /* Skip it, get next. */
266 | switch (state) {
267 | case 0: /* Invalid = in first position */
268 | case 1: /* Invalid = in second position */
269 | return (-1);
270 |
271 | case 2: /* Valid, means one byte of info */
272 | /* Skip any number of spaces. */
273 | for (; ch != '\0'; ch = *src++)
274 | if (!isspace(ch))
275 | break;
276 | /* Make sure there is another trailing = sign. */
277 | if (ch != Pad64)
278 | return (-1);
279 | ch = *src++; /* Skip the = */
280 | /* Fall through to "single trailing =" case. */
281 | /* FALLTHROUGH */
282 |
283 | case 3: /* Valid, means two bytes of info */
284 | /*
285 | * We know this char is an =. Is there anything but
286 | * whitespace after it?
287 | */
288 | for (; ch != '\0'; ch = *src++)
289 | if (!isspace(ch))
290 | return (-1);
291 |
292 | /*
293 | * Now make sure for cases 2 and 3 that the "extra"
294 | * bits that slopped past the last full byte were
295 | * zeros. If we don't check them, they become a
296 | * subliminal channel.
297 | */
298 | if (target && target[tarindex] != 0)
299 | return (-1);
300 | }
301 | } else {
302 | /*
303 | * We ended by seeing the end of the string. Make sure we
304 | * have no partial bytes lying around.
305 | */
306 | if (state != 0)
307 | return (-1);
308 | }
309 |
310 | return (tarindex);
311 | }
312 |
313 | #endif /* !defined(HAVE_B64_PTON) && !defined(HAVE___B64_PTON) */
314 | #endif
315 |
--------------------------------------------------------------------------------
/ios-app/Mobile Chat/SocketRocket-master/SocketRocket/base64.h:
--------------------------------------------------------------------------------
1 | // Copyright 2012 Square Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | //
15 |
16 |
17 | #ifndef SocketRocket_base64_h
18 | #define SocketRocket_base64_h
19 |
20 | #include
21 |
22 | extern int
23 | b64_ntop(u_char const *src,
24 | size_t srclength,
25 | char *target,
26 | size_t targsize);
27 |
28 | extern int
29 | b64_pton(char const *src,
30 | u_char *target,
31 | size_t targsize);
32 |
33 |
34 | #endif
35 |
--------------------------------------------------------------------------------
/nodejs-server/mobile-chat.js:
--------------------------------------------------------------------------------
1 | /*
2 | Mobile Chat (ff-mobile-chat) is a cross platform
3 | (Android, iOS, Windows Phone 8, web) chat supported by NodeJS websockets.
4 |
5 |
6 | Copyright (C) 2013-2014 Terry Wahl & Marco Jacobs
7 |
8 | This program is free software: you can redistribute it and/or modify
9 | it under the terms of the GNU Affero General Public License as
10 | published by the Free Software Foundation, either version 3 of the
11 | License, or (at your option) any later version.
12 |
13 | This program is distributed in the hope that it will be useful,
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | GNU Affero General Public License for more details.
17 |
18 | You should have received a copy of the GNU Affero General Public License
19 | along with this program. If not, see .
20 | */
21 |
22 | //vars
23 | var http = require('http'),
24 | sockjs = require('sockjs'),
25 | mobileChat = sockjs.createServer(),
26 | connections = [];
27 |
28 | //configure message relays
29 | mobileChat.on('connection', function (conn) {
30 | console.log('New connection');
31 | connections.push(conn);
32 | conn.on('data', function (message) {
33 | console.log('New data: ' + message);
34 | // send message to all connections
35 | for (var i = 0; i < connections.length; i++) {
36 | connections[i].write(message);
37 | }
38 | });
39 | conn.on('close', function () {
40 | connections.splice(connections.indexOf(conn), 1);
41 | console.log('Closed connection');
42 | });
43 | });
44 |
45 | //server loc
46 | var server = http.createServer();
47 | mobileChat.installHandlers(server, {
48 | prefix: '/mobilechat'
49 | });
50 | //location is self
51 | server.listen(6975, '0.0.0.0');
--------------------------------------------------------------------------------
/webclient/box.css:
--------------------------------------------------------------------------------
1 | /*
2 | Mobile Chat (ff-mobile-chat) is a cross platform
3 | (Android, iOS, Windows Phone 8, web) chat supported by NodeJS websockets.
4 |
5 |
6 | Copyright (C) 2013-2014 Terry Wahl & Marco Jacobs
7 |
8 | This program is free software: you can redistribute it and/or modify
9 | it under the terms of the GNU Affero General Public License as
10 | published by the Free Software Foundation, either version 3 of the
11 | License, or (at your option) any later version.
12 |
13 | This program is distributed in the hope that it will be useful,
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | GNU Affero General Public License for more details.
17 |
18 | You should have received a copy of the GNU Affero General Public License
19 | along with this program. If not, see .
20 | */
21 |
22 | #signInForm, #messageForm {
23 | margin: 0px;
24 | margin-bottom: 1px;
25 | }
26 | #userName {
27 | width: 150px;
28 | height: 22px;
29 | border: 1px teal solid;
30 | float: left;
31 | }
32 | #changeNameButton {
33 | width: 100px;
34 | height: 22px;
35 | }
36 | #chatBox {
37 | font-family: tahoma;
38 | font-size: 12px;
39 | color: black;
40 | border: 1px teal solid;
41 | height: 225px;
42 | width: 400px;
43 | overflow: scroll;
44 | margin-left: 1px;
45 | }
46 | #message {
47 | width: 350px;
48 | height: 22px;
49 | border: 1px teal solid;
50 | float: left;
51 | margin-left: 1px;
52 | margin-top: 1px;
53 | }
54 | #send {
55 | width: 50px;
56 | height: 22px;
57 | float: left;
58 | margin: 1px;
59 | }
60 | .disconnected {
61 | color: red;
62 | }
63 | .connected {
64 | color: green;
65 | }
--------------------------------------------------------------------------------
/webclient/index.html:
--------------------------------------------------------------------------------
1 |
21 |
22 |
23 |
24 |
25 | Mobile Chat
26 |
27 |
28 |
29 |
30 | Mobile Chat
31 |
32 |
Status:
33 | Disconnected
34 |
35 |
36 |
40 |
41 |
42 |
43 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/webclient/mobile-chat.js:
--------------------------------------------------------------------------------
1 | /*
2 | Mobile Chat (ff-mobile-chat) is a cross platform
3 | (Android, iOS, Windows Phone 8, web) chat supported by NodeJS websockets.
4 |
5 |
6 | Copyright (C) 2013-2014 Terry Wahl & Marco Jacobs
7 |
8 | This program is free software: you can redistribute it and/or modify
9 | it under the terms of the GNU Affero General Public License as
10 | published by the Free Software Foundation, either version 3 of the
11 | License, or (at your option) any later version.
12 |
13 | This program is distributed in the hope that it will be useful,
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | GNU Affero General Public License for more details.
17 |
18 | You should have received a copy of the GNU Affero General Public License
19 | along with this program. If not, see .
20 | */
21 |
22 | (function () {
23 | var connectToServer = function () {
24 | //Connect to your server here
25 | var mobileChatSocket = new SockJS('http://your.server:6975/mobilechat');
26 |
27 | mobileChatSocket.onopen = function () {
28 | clearInterval(connectRetry);
29 | $('.connect-status')
30 | .removeClass('disconnected')
31 | .addClass('connected')
32 | .text('Connected');
33 | };
34 |
35 | //Receive message from server
36 | mobileChatSocket.onmessage = function (e) {
37 | $('#chatBox').html($('#chatBox').html() + '' + e.data);
38 | var objDiv = document.getElementById('chatBox');
39 | objDiv.scrollTop = objDiv.scrollHeight;
40 | };
41 |
42 | mobileChatSocket.onclose = function () {
43 | clearInterval(connectRetry);
44 | connectRetry = setInterval(connectToServer, 1000);
45 | $('.connect-status')
46 | .removeClass('connected')
47 | .addClass('disconnected')
48 | .text('Disconnected');
49 | };
50 |
51 | //Send your message to the server.
52 | $('#sendButton').on('click', function () {
53 | if ($('#userName').val() != '') {
54 | if ($('#messageBox').val() != '') {
55 | mobileChatSocket.send($('#userName').val() + ': ' + $('#messageBox').val());
56 | document.getElementById("messageBox").value = '';
57 | }
58 | } else {
59 | $('#chatBox').html($('#chatBox').html() + '' + 'Please put you name in box above!');
60 | var objDiv = document.getElementById('chatBox');
61 | objDiv.scrollTop = objDiv.scrollHeight;
62 | }
63 | });
64 |
65 | //Prevent enter refreshing the page, it sends the text from now on
66 | $('#messageBox').keydown(function (e) {
67 | if (e.keyCode == 13) { // 13 is enter
68 | if ($('#userName').val() != '') {
69 | if ($('#messageBox').val() != '') {
70 | mobileChatSocket.send($('#userName').val() + ': ' + $('#messageBox').val());
71 | document.getElementById("messageBox").value = '';
72 | }
73 | } else {
74 | $('#chatBox').html($('#chatBox').html() + '' + 'Please put you name in box above!');
75 | var objDiv = document.getElementById('chatBox');
76 | objDiv.scrollTop = objDiv.scrollHeight;
77 | }
78 | return false;
79 | }
80 | });
81 |
82 | //Prevent enter refreshing the page
83 | $('#messageBox').keydown(function (e) {
84 | if (e.keyCode == 13) { // 13 is enter
85 |
86 | return false;
87 | }
88 | });
89 | };
90 |
91 | var connectRetry = setInterval(connectToServer, 1000);
92 | })();
--------------------------------------------------------------------------------
/windows-phone-8/MobileChat/MobileChat.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2013
4 | VisualStudioVersion = 12.0.21005.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MobileChat", "MobileChat\MobileChat.csproj", "{BC8CA4C4-BA0A-4809-BCDE-51E309B3EEF6}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Debug|ARM = Debug|ARM
12 | Debug|x86 = Debug|x86
13 | Release|Any CPU = Release|Any CPU
14 | Release|ARM = Release|ARM
15 | Release|x86 = Release|x86
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {BC8CA4C4-BA0A-4809-BCDE-51E309B3EEF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {BC8CA4C4-BA0A-4809-BCDE-51E309B3EEF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {BC8CA4C4-BA0A-4809-BCDE-51E309B3EEF6}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
21 | {BC8CA4C4-BA0A-4809-BCDE-51E309B3EEF6}.Debug|ARM.ActiveCfg = Debug|ARM
22 | {BC8CA4C4-BA0A-4809-BCDE-51E309B3EEF6}.Debug|ARM.Build.0 = Debug|ARM
23 | {BC8CA4C4-BA0A-4809-BCDE-51E309B3EEF6}.Debug|ARM.Deploy.0 = Debug|ARM
24 | {BC8CA4C4-BA0A-4809-BCDE-51E309B3EEF6}.Debug|x86.ActiveCfg = Debug|x86
25 | {BC8CA4C4-BA0A-4809-BCDE-51E309B3EEF6}.Debug|x86.Build.0 = Debug|x86
26 | {BC8CA4C4-BA0A-4809-BCDE-51E309B3EEF6}.Debug|x86.Deploy.0 = Debug|x86
27 | {BC8CA4C4-BA0A-4809-BCDE-51E309B3EEF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
28 | {BC8CA4C4-BA0A-4809-BCDE-51E309B3EEF6}.Release|Any CPU.Build.0 = Release|Any CPU
29 | {BC8CA4C4-BA0A-4809-BCDE-51E309B3EEF6}.Release|Any CPU.Deploy.0 = Release|Any CPU
30 | {BC8CA4C4-BA0A-4809-BCDE-51E309B3EEF6}.Release|ARM.ActiveCfg = Release|ARM
31 | {BC8CA4C4-BA0A-4809-BCDE-51E309B3EEF6}.Release|ARM.Build.0 = Release|ARM
32 | {BC8CA4C4-BA0A-4809-BCDE-51E309B3EEF6}.Release|ARM.Deploy.0 = Release|ARM
33 | {BC8CA4C4-BA0A-4809-BCDE-51E309B3EEF6}.Release|x86.ActiveCfg = Release|x86
34 | {BC8CA4C4-BA0A-4809-BCDE-51E309B3EEF6}.Release|x86.Build.0 = Release|x86
35 | {BC8CA4C4-BA0A-4809-BCDE-51E309B3EEF6}.Release|x86.Deploy.0 = Release|x86
36 | EndGlobalSection
37 | GlobalSection(SolutionProperties) = preSolution
38 | HideSolutionNode = FALSE
39 | EndGlobalSection
40 | EndGlobal
41 |
--------------------------------------------------------------------------------
/windows-phone-8/MobileChat/MobileChat/App.xaml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/windows-phone-8/MobileChat/MobileChat/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Resources;
4 | using System.Windows;
5 | using System.Windows.Markup;
6 | using System.Windows.Navigation;
7 | using Microsoft.Phone.Controls;
8 | using Microsoft.Phone.Shell;
9 | using MobileChat.Resources;
10 |
11 | namespace MobileChat
12 | {
13 | public partial class App : Application
14 | {
15 | ///
16 | /// Provides easy access to the root frame of the Phone Application.
17 | ///
18 | /// The root frame of the Phone Application.
19 | public static PhoneApplicationFrame RootFrame { get; private set; }
20 |
21 | ///
22 | /// Constructor for the Application object.
23 | ///
24 | public App()
25 | {
26 | // Global handler for uncaught exceptions.
27 | UnhandledException += Application_UnhandledException;
28 |
29 | // Standard XAML initialization
30 | InitializeComponent();
31 |
32 | // Phone-specific initialization
33 | InitializePhoneApplication();
34 |
35 | // Language display initialization
36 | InitializeLanguage();
37 |
38 | // Show graphics profiling information while debugging.
39 | if (Debugger.IsAttached)
40 | {
41 | // Display the current frame rate counters.
42 | Application.Current.Host.Settings.EnableFrameRateCounter = true;
43 |
44 | // Show the areas of the app that are being redrawn in each frame.
45 | //Application.Current.Host.Settings.EnableRedrawRegions = true;
46 |
47 | // Enable non-production analysis visualization mode,
48 | // which shows areas of a page that are handed off to GPU with a colored overlay.
49 | //Application.Current.Host.Settings.EnableCacheVisualization = true;
50 |
51 | // Prevent the screen from turning off while under the debugger by disabling
52 | // the application's idle detection.
53 | // Caution:- Use this under debug mode only. Application that disables user idle detection will continue to run
54 | // and consume battery power when the user is not using the phone.
55 | PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled;
56 | }
57 |
58 | }
59 |
60 | // Code to execute when the application is launching (eg, from Start)
61 | // This code will not execute when the application is reactivated
62 | private void Application_Launching(object sender, LaunchingEventArgs e)
63 | {
64 | }
65 |
66 | // Code to execute when the application is activated (brought to foreground)
67 | // This code will not execute when the application is first launched
68 | private void Application_Activated(object sender, ActivatedEventArgs e)
69 | {
70 | }
71 |
72 | // Code to execute when the application is deactivated (sent to background)
73 | // This code will not execute when the application is closing
74 | private void Application_Deactivated(object sender, DeactivatedEventArgs e)
75 | {
76 | }
77 |
78 | // Code to execute when the application is closing (eg, user hit Back)
79 | // This code will not execute when the application is deactivated
80 | private void Application_Closing(object sender, ClosingEventArgs e)
81 | {
82 | }
83 |
84 | // Code to execute if a navigation fails
85 | private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
86 | {
87 | if (Debugger.IsAttached)
88 | {
89 | // A navigation has failed; break into the debugger
90 | Debugger.Break();
91 | }
92 | }
93 |
94 | // Code to execute on Unhandled Exceptions
95 | private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
96 | {
97 | if (Debugger.IsAttached)
98 | {
99 | // An unhandled exception has occurred; break into the debugger
100 | Debugger.Break();
101 | }
102 | }
103 |
104 | #region Phone application initialization
105 |
106 | // Avoid double-initialization
107 | private bool phoneApplicationInitialized = false;
108 |
109 | // Do not add any additional code to this method
110 | private void InitializePhoneApplication()
111 | {
112 | if (phoneApplicationInitialized)
113 | return;
114 |
115 | // Create the frame but don't set it as RootVisual yet; this allows the splash
116 | // screen to remain active until the application is ready to render.
117 | RootFrame = new PhoneApplicationFrame();
118 | RootFrame.Navigated += CompleteInitializePhoneApplication;
119 |
120 | // Handle navigation failures
121 | RootFrame.NavigationFailed += RootFrame_NavigationFailed;
122 |
123 | // Handle reset requests for clearing the backstack
124 | RootFrame.Navigated += CheckForResetNavigation;
125 |
126 | // Ensure we don't initialize again
127 | phoneApplicationInitialized = true;
128 | }
129 |
130 | // Do not add any additional code to this method
131 | private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e)
132 | {
133 | // Set the root visual to allow the application to render
134 | if (RootVisual != RootFrame)
135 | RootVisual = RootFrame;
136 |
137 | // Remove this handler since it is no longer needed
138 | RootFrame.Navigated -= CompleteInitializePhoneApplication;
139 | }
140 |
141 | private void CheckForResetNavigation(object sender, NavigationEventArgs e)
142 | {
143 | // If the app has received a 'reset' navigation, then we need to check
144 | // on the next navigation to see if the page stack should be reset
145 | if (e.NavigationMode == NavigationMode.Reset)
146 | RootFrame.Navigated += ClearBackStackAfterReset;
147 | }
148 |
149 | private void ClearBackStackAfterReset(object sender, NavigationEventArgs e)
150 | {
151 | // Unregister the event so it doesn't get called again
152 | RootFrame.Navigated -= ClearBackStackAfterReset;
153 |
154 | // Only clear the stack for 'new' (forward) and 'refresh' navigations
155 | if (e.NavigationMode != NavigationMode.New && e.NavigationMode != NavigationMode.Refresh)
156 | return;
157 |
158 | // For UI consistency, clear the entire page stack
159 | while (RootFrame.RemoveBackEntry() != null)
160 | {
161 | ; // do nothing
162 | }
163 | }
164 |
165 | #endregion
166 |
167 | // Initialize the app's font and flow direction as defined in its localized resource strings.
168 | //
169 | // To ensure that the font of your application is aligned with its supported languages and that the
170 | // FlowDirection for each of those languages follows its traditional direction, ResourceLanguage
171 | // and ResourceFlowDirection should be initialized in each resx file to match these values with that
172 | // file's culture. For example:
173 | //
174 | // AppResources.es-ES.resx
175 | // ResourceLanguage's value should be "es-ES"
176 | // ResourceFlowDirection's value should be "LeftToRight"
177 | //
178 | // AppResources.ar-SA.resx
179 | // ResourceLanguage's value should be "ar-SA"
180 | // ResourceFlowDirection's value should be "RightToLeft"
181 | //
182 | // For more info on localizing Windows Phone apps see http://go.microsoft.com/fwlink/?LinkId=262072.
183 | //
184 | private void InitializeLanguage()
185 | {
186 | try
187 | {
188 | // Set the font to match the display language defined by the
189 | // ResourceLanguage resource string for each supported language.
190 | //
191 | // Fall back to the font of the neutral language if the Display
192 | // language of the phone is not supported.
193 | //
194 | // If a compiler error is hit then ResourceLanguage is missing from
195 | // the resource file.
196 | RootFrame.Language = XmlLanguage.GetLanguage(AppResources.ResourceLanguage);
197 |
198 | // Set the FlowDirection of all elements under the root frame based
199 | // on the ResourceFlowDirection resource string for each
200 | // supported language.
201 | //
202 | // If a compiler error is hit then ResourceFlowDirection is missing from
203 | // the resource file.
204 | FlowDirection flow = (FlowDirection)Enum.Parse(typeof(FlowDirection), AppResources.ResourceFlowDirection);
205 | RootFrame.FlowDirection = flow;
206 | }
207 | catch
208 | {
209 | // If an exception is caught here it is most likely due to either
210 | // ResourceLangauge not being correctly set to a supported language
211 | // code or ResourceFlowDirection is set to a value other than LeftToRight
212 | // or RightToLeft.
213 |
214 | if (Debugger.IsAttached)
215 | {
216 | Debugger.Break();
217 | }
218 |
219 | throw;
220 | }
221 | }
222 | }
223 | }
--------------------------------------------------------------------------------
/windows-phone-8/MobileChat/MobileChat/Assets/AlignmentGrid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TerryWahl/Mobile-Multiplatform-Websockets-Android-iOS-Windows-Phone-Web/10d3a2dc8947166040671affe8ec79e73ebca6f8/windows-phone-8/MobileChat/MobileChat/Assets/AlignmentGrid.png
--------------------------------------------------------------------------------
/windows-phone-8/MobileChat/MobileChat/Assets/ApplicationIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TerryWahl/Mobile-Multiplatform-Websockets-Android-iOS-Windows-Phone-Web/10d3a2dc8947166040671affe8ec79e73ebca6f8/windows-phone-8/MobileChat/MobileChat/Assets/ApplicationIcon.png
--------------------------------------------------------------------------------
/windows-phone-8/MobileChat/MobileChat/Assets/Tiles/FlipCycleTileLarge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TerryWahl/Mobile-Multiplatform-Websockets-Android-iOS-Windows-Phone-Web/10d3a2dc8947166040671affe8ec79e73ebca6f8/windows-phone-8/MobileChat/MobileChat/Assets/Tiles/FlipCycleTileLarge.png
--------------------------------------------------------------------------------
/windows-phone-8/MobileChat/MobileChat/Assets/Tiles/FlipCycleTileMedium.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TerryWahl/Mobile-Multiplatform-Websockets-Android-iOS-Windows-Phone-Web/10d3a2dc8947166040671affe8ec79e73ebca6f8/windows-phone-8/MobileChat/MobileChat/Assets/Tiles/FlipCycleTileMedium.png
--------------------------------------------------------------------------------
/windows-phone-8/MobileChat/MobileChat/Assets/Tiles/FlipCycleTileSmall.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TerryWahl/Mobile-Multiplatform-Websockets-Android-iOS-Windows-Phone-Web/10d3a2dc8947166040671affe8ec79e73ebca6f8/windows-phone-8/MobileChat/MobileChat/Assets/Tiles/FlipCycleTileSmall.png
--------------------------------------------------------------------------------
/windows-phone-8/MobileChat/MobileChat/Assets/Tiles/IconicTileMediumLarge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TerryWahl/Mobile-Multiplatform-Websockets-Android-iOS-Windows-Phone-Web/10d3a2dc8947166040671affe8ec79e73ebca6f8/windows-phone-8/MobileChat/MobileChat/Assets/Tiles/IconicTileMediumLarge.png
--------------------------------------------------------------------------------
/windows-phone-8/MobileChat/MobileChat/Assets/Tiles/IconicTileSmall.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TerryWahl/Mobile-Multiplatform-Websockets-Android-iOS-Windows-Phone-Web/10d3a2dc8947166040671affe8ec79e73ebca6f8/windows-phone-8/MobileChat/MobileChat/Assets/Tiles/IconicTileSmall.png
--------------------------------------------------------------------------------
/windows-phone-8/MobileChat/MobileChat/LocalizedStrings.cs:
--------------------------------------------------------------------------------
1 | using MobileChat.Resources;
2 |
3 | namespace MobileChat
4 | {
5 | ///
6 | /// Provides access to string resources.
7 | ///
8 | public class LocalizedStrings
9 | {
10 | private static AppResources _localizedResources = new AppResources();
11 |
12 | public AppResources LocalizedResources { get { return _localizedResources; } }
13 | }
14 | }
--------------------------------------------------------------------------------
/windows-phone-8/MobileChat/MobileChat/MobileChat.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 10.0.20506
7 | 2.0
8 | {BC8CA4C4-BA0A-4809-BCDE-51E309B3EEF6}
9 | {C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}
10 | Library
11 | Properties
12 | MobileChat
13 | MobileChat
14 | WindowsPhone
15 | v8.0
16 | $(TargetFrameworkVersion)
17 | true
18 |
19 |
20 | true
21 | true
22 | MobileChat_$(Configuration)_$(Platform).xap
23 | Properties\AppManifest.xml
24 | MobileChat.App
25 | true
26 | 11.0
27 | true
28 |
29 |
30 | true
31 | full
32 | false
33 | Bin\Debug
34 | DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE
35 | true
36 | true
37 | prompt
38 | 4
39 |
40 |
41 | pdbonly
42 | true
43 | Bin\Release
44 | TRACE;SILVERLIGHT;WINDOWS_PHONE
45 | true
46 | true
47 | prompt
48 | 4
49 |
50 |
51 | true
52 | full
53 | false
54 | Bin\x86\Debug
55 | DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE
56 | true
57 | true
58 | prompt
59 | 4
60 |
61 |
62 | pdbonly
63 | true
64 | Bin\x86\Release
65 | TRACE;SILVERLIGHT;WINDOWS_PHONE
66 | true
67 | true
68 | prompt
69 | 4
70 |
71 |
72 | true
73 | full
74 | false
75 | Bin\ARM\Debug
76 | DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE
77 | true
78 | true
79 | prompt
80 | 4
81 |
82 |
83 | pdbonly
84 | true
85 | Bin\ARM\Release
86 | TRACE;SILVERLIGHT;WINDOWS_PHONE
87 | true
88 | true
89 | prompt
90 | 4
91 |
92 |
93 |
94 | App.xaml
95 |
96 |
97 |
98 | MobileChat.xaml
99 |
100 |
101 |
102 | True
103 | True
104 | AppResources.resx
105 |
106 |
107 |
108 |
109 | Designer
110 | MSBuild:Compile
111 |
112 |
113 | Designer
114 | MSBuild:Compile
115 |
116 |
117 |
118 |
119 |
120 | Designer
121 |
122 |
123 |
124 |
125 |
126 | PreserveNewest
127 |
128 |
129 | PreserveNewest
130 |
131 |
132 | PreserveNewest
133 |
134 |
135 | PreserveNewest
136 |
137 |
138 | PreserveNewest
139 |
140 |
141 | PreserveNewest
142 |
143 |
144 |
145 |
146 |
147 | PublicResXFileCodeGenerator
148 | AppResources.Designer.cs
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
164 |
165 |
--------------------------------------------------------------------------------
/windows-phone-8/MobileChat/MobileChat/MobileChat.xaml:
--------------------------------------------------------------------------------
1 |
21 |
22 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/windows-phone-8/MobileChat/MobileChat/MobileChat.xaml.cs:
--------------------------------------------------------------------------------
1 | /*
2 | Mobile Chat (ff-mobile-chat) is a cross platform
3 | (Android, iOS, Windows Phone 8, web) chat supported by NodeJS websockets.
4 |
5 |
6 | Copyright (C) 2013-2014 Terry Wahl & Marco Jacobs
7 |
8 | This program is free software: you can redistribute it and/or modify
9 | it under the terms of the GNU Affero General Public License as
10 | published by the Free Software Foundation, either version 3 of the
11 | License, or (at your option) any later version.
12 |
13 | This program is distributed in the hope that it will be useful,
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | GNU Affero General Public License for more details.
17 |
18 | You should have received a copy of the GNU Affero General Public License
19 | along with this program. If not, see .
20 | */
21 |
22 | using System;
23 | using System.Collections.Generic;
24 | using System.Linq;
25 | using System.Net;
26 | using System.Windows;
27 | using System.Windows.Controls;
28 | using System.Windows.Navigation;
29 | using Microsoft.Phone.Controls;
30 | using Microsoft.Phone.Shell;
31 | using MobileChat.Resources;
32 | using System.Windows.Threading;
33 | using WebSocket4Net;
34 | using SuperSocket.ClientEngine;
35 |
36 | namespace MobileChat
37 | {
38 | public partial class MobileChat : PhoneApplicationPage
39 | {
40 | //This library requires a raw websocket url.
41 | //For NodeJS with SockJS this should be "ws://YOUR.URL:PORT/IDENTIFIER/websocket"
42 | private readonly String webSocketLink = "ws://your.site:6975/mobilechat/websocket";
43 |
44 | private WebSocket websocket;
45 | private bool socketOpen = false;
46 |
47 | public MobileChat()
48 | {
49 | InitializeComponent();
50 |
51 | //Init the websocket
52 | websocket = new WebSocket(webSocketLink);
53 | websocket.Opened += new EventHandler(websocket_Opened);
54 | websocket.Error += new EventHandler(websocket_Error);
55 | websocket.Closed += new EventHandler(websocket_Closed);
56 | websocket.MessageReceived += new EventHandler(websocket_MessageReceived);
57 | websocket.Open();
58 | }
59 |
60 | private void btSend_Click(object sender, RoutedEventArgs e)
61 | {
62 | //Wait for socket to open
63 | if (socketOpen)
64 | {
65 | //Check name is not Name (default) and not empty
66 | if (_tbxName.Text == "Name" || _tbxName.Text == "")
67 | {
68 | addMessageToChatBox("Please put you name in box above!");
69 | }
70 | else if (_tbxMessage.Text != "")
71 | {
72 | //If message is not empty, send the message
73 | string message = _tbxName.Text + ": " + _tbxMessage.Text;
74 | _tbxMessage.Text = "";
75 | websocket.Send(message);
76 | }
77 | }
78 | }
79 |
80 | private void addMessageToChatBox(string message)
81 | {
82 | //Add message to chat box.
83 | TextBlock tbNewChat = new TextBlock();
84 | tbNewChat.TextWrapping = TextWrapping.Wrap;
85 | tbNewChat.Text = message;
86 | _svChatbox.Children.Add(tbNewChat);
87 | _svChatboxHolder.ScrollToVerticalOffset(_svChatboxHolder.ExtentHeight);
88 | }
89 |
90 | private void websocket_MessageReceived(object sender, MessageReceivedEventArgs e)
91 | {
92 | //Dispatcher is needed to work on the UI thread.
93 | Dispatcher.BeginInvoke(() =>
94 | {
95 | addMessageToChatBox(e.Message);
96 | });
97 | }
98 |
99 | private void websocket_Closed(object sender, EventArgs e)
100 | {
101 | socketOpen = false;
102 | }
103 |
104 | private void websocket_Error(object sender, ErrorEventArgs e)
105 | {
106 | //This should be used...
107 | }
108 |
109 | private void websocket_Opened(object sender, EventArgs e)
110 | {
111 | socketOpen = true;
112 | }
113 | }
114 | }
--------------------------------------------------------------------------------
/windows-phone-8/MobileChat/MobileChat/Properties/AppManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/windows-phone-8/MobileChat/MobileChat/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 | using System.Resources;
5 |
6 | // General Information about an assembly is controlled through the following
7 | // set of attributes. Change these attribute values to modify the information
8 | // associated with an assembly.
9 | [assembly: AssemblyTitle("MobileChat")]
10 | [assembly: AssemblyDescription("")]
11 | [assembly: AssemblyConfiguration("")]
12 | [assembly: AssemblyCompany("")]
13 | [assembly: AssemblyProduct("MobileChat")]
14 | [assembly: AssemblyCopyright("Copyright © 2013")]
15 | [assembly: AssemblyTrademark("")]
16 | [assembly: AssemblyCulture("")]
17 |
18 | // Setting ComVisible to false makes the types in this assembly not visible
19 | // to COM components. If you need to access a type in this assembly from
20 | // COM, set the ComVisible attribute to true on that type.
21 | [assembly: ComVisible(false)]
22 |
23 | // The following GUID is for the ID of the typelib if this project is exposed to COM
24 | [assembly: Guid("64332422-3e44-4763-9d83-960ade00fe32")]
25 |
26 | // Version information for an assembly consists of the following four values:
27 | //
28 | // Major Version
29 | // Minor Version
30 | // Build Number
31 | // Revision
32 | //
33 | // You can specify all the values or you can default the Revision and Build Numbers
34 | // by using the '*' as shown below:
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 | [assembly: NeutralResourcesLanguageAttribute("en-US")]
38 |
--------------------------------------------------------------------------------
/windows-phone-8/MobileChat/MobileChat/Properties/WMAppManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Assets\ApplicationIcon.png
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | Assets\Tiles\FlipCycleTileSmall.png
20 | 0
21 | Assets\Tiles\FlipCycleTileMedium.png
22 | MobileChat
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/windows-phone-8/MobileChat/MobileChat/Resources/AppResources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.17626
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace MobileChat.Resources
12 | {
13 | using System;
14 |
15 |
16 | ///
17 | /// A strongly-typed resource class, for looking up localized strings, etc.
18 | ///
19 | // This class was auto-generated by the StronglyTypedResourceBuilder
20 | // class via a tool like ResGen or Visual Studio.
21 | // To add or remove a member, edit your .ResX file then rerun ResGen
22 | // with the /str option, or rebuild your VS project.
23 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
24 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
25 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
26 | public class AppResources
27 | {
28 |
29 | private static global::System.Resources.ResourceManager resourceMan;
30 |
31 | private static global::System.Globalization.CultureInfo resourceCulture;
32 |
33 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
34 | internal AppResources()
35 | {
36 | }
37 |
38 | ///
39 | /// Returns the cached ResourceManager instance used by this class.
40 | ///
41 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
42 | public static global::System.Resources.ResourceManager ResourceManager
43 | {
44 | get
45 | {
46 | if (object.ReferenceEquals(resourceMan, null))
47 | {
48 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MobileChat.Resources.AppResources", typeof(AppResources).Assembly);
49 | resourceMan = temp;
50 | }
51 | return resourceMan;
52 | }
53 | }
54 |
55 | ///
56 | /// Overrides the current thread's CurrentUICulture property for all
57 | /// resource lookups using this strongly typed resource class.
58 | ///
59 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
60 | public static global::System.Globalization.CultureInfo Culture
61 | {
62 | get
63 | {
64 | return resourceCulture;
65 | }
66 | set
67 | {
68 | resourceCulture = value;
69 | }
70 | }
71 |
72 | ///
73 | /// Looks up a localized string similar to LeftToRight.
74 | ///
75 | public static string ResourceFlowDirection
76 | {
77 | get
78 | {
79 | return ResourceManager.GetString("ResourceFlowDirection", resourceCulture);
80 | }
81 | }
82 |
83 | ///
84 | /// Looks up a localized string similar to us-EN.
85 | ///
86 | public static string ResourceLanguage
87 | {
88 | get
89 | {
90 | return ResourceManager.GetString("ResourceLanguage", resourceCulture);
91 | }
92 | }
93 |
94 | ///
95 | /// Looks up a localized string similar to MY APPLICATION.
96 | ///
97 | public static string ApplicationTitle
98 | {
99 | get
100 | {
101 | return ResourceManager.GetString("ApplicationTitle", resourceCulture);
102 | }
103 | }
104 |
105 | ///
106 | /// Looks up a localized string similar to button.
107 | ///
108 | public static string AppBarButtonText
109 | {
110 | get
111 | {
112 | return ResourceManager.GetString("AppBarButtonText", resourceCulture);
113 | }
114 | }
115 |
116 | ///
117 | /// Looks up a localized string similar to menu item.
118 | ///
119 | public static string AppBarMenuItemText
120 | {
121 | get
122 | {
123 | return ResourceManager.GetString("AppBarMenuItemText", resourceCulture);
124 | }
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/windows-phone-8/MobileChat/MobileChat/Resources/AppResources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | LeftToRight
122 | Controls the FlowDirection for all elements in the RootFrame. Set to the traditional direction of this resource file's language
123 |
124 |
125 | en-US
126 | Controls the Language and ensures that the font for all elements in the RootFrame aligns with the app's language. Set to the language code of this resource file's language.
127 |
128 |
129 | MY APPLICATION
130 |
131 |
132 | add
133 |
134 |
135 | Menu Item
136 |
137 |
--------------------------------------------------------------------------------
/windows-phone-8/MobileChat/MobileChat/libs/WebSocket4Net.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TerryWahl/Mobile-Multiplatform-Websockets-Android-iOS-Windows-Phone-Web/10d3a2dc8947166040671affe8ec79e73ebca6f8/windows-phone-8/MobileChat/MobileChat/libs/WebSocket4Net.dll
--------------------------------------------------------------------------------