XMPP Sending/Receving file in iphone sdk ...? - iphone

How to send/receive file in iphone sdk using xmpp framework ?
Currently i am using XEP-0065 classes, and use the following code:
ObjTURNSocket = [[TURNSocket alloc] initWithStream:((TestAppDelegate*)[[UIApplication sharedApplication] delegate]).xmppStream
toJID:chatuser.jid];
[ObjTURNSocket start:self];
And I am getting following response from the server:
<iq type="error" id="AB2ED567-B97F-4DFE-B789-7731A617C239" to="kapil#testweb/6df6dc96" from="jabber.org">
<query xmlns="http://jabber.org/protocol/disco#items"/>
<error code="404" type="cancel">
<remote-server-not-found xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>
</error>
</iq>`
Any help or suggestion will be well appreciated.

First, call setProxyCandidates with an array of the possible servers that you might be able to use for proxying. The default is "jabber.org", and your server is not federated with jabber.org, which is why you are getting the disco error back.
Next, in your delegate, implement the following methods:
- (void)turnSocket:(TURNSocket *)sender didSucceed:(GCDAsyncSocket *)socket;
- (void)turnSocketDidFail:(TURNSocket *)sender;
Then, in your didSucceed implementation, send data on the socket that was passed in, using:
- (void)writeData:(NSData *)data
withTimeout:(NSTimeInterval)timeout
tag:(long)tag;
Finally, close the socket:
- (void)disconnectAfterWriting;
I figured this out by looking at the source for TURNSocket.m, looking for the hardcoded "jabber.org", then searching for [delegate to find the places the delegate was getting called. This took me back to TURNSocket.h, which had a protocol documented for the delegate to implement.

I ended up having to customize the TURNSocket class to meet my specific needs to be able to transfer a file from my iOS device to another device. If there is a proxy server available, then the TURNSocket class might work for one's needs. But if this is a direct connection where a proxy server may not be available, then some extra work is necessary to set up your device to be able to connect to another device and directly transfer a file.
I was able to receive a file using TURNSocket in its current form with only one minor modification. As the code currently stands, the id and sid are assigned the same value, which cannot be guaranteed that a received stanza will have the same unique identifier value for both the id and sid.

You should have use xep-96 to make it possible to share and receive files.
after that just initiate xmppSifiletranfer with relevant data.
like
-(void)sendToOtherDevice:(NSData *)fileData receiverJid:(XmPPJId *)senderFullID file:(NSString *)fileName{
myFileTransferID=[xmppStream generateUUID];
XMPPJID *jid =senderFullID;
sifiletransfer=[[XMPPSIFileTransfer alloc]init];
[sifiletransfer initiateFileTransferTo:jid withData:fileData file:fileName passedsid:myFileTransferID];
if ([jid.domain isEqualToString:[xmppStream myJID].domain]) {
[TURNSocket setProxyCandidates:[NSArray arrayWithObjects:jid.domain, nil]];
} else {
[TURNSocket setProxyCandidates:[NSArray arrayWithObjects:jid.domain,[xmppStream myJID].domain, nil]];
}
TURNSocket *socket = [[TURNSocket alloc] initWithStream:xmppStream toJID:jid sid:myFileTransferID];
// [socket setDataToSend:fileData];
[socket startWithDelegate:self delegateQueue:dispatch_get_main_queue()];
}
# delegater of turnsocket
- (void)turnSocket:(TURNSocket *)sender didSucceed:(GCDAsyncSocket *)socket
{
NSLog(#"Socket Suceeed Port For File Transfer: %d",socket.localPort);
DDLogInfo(#"TURN Connection succeeded!");
DDLogInfo(#"You now have a socket that you can use to send/receive data to/from the other person.");
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Hurray!!"
message:#"Conection Established"
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alertView show];
}
if you guys have any other issue regarding file transfer comment below.I will surely help you.

Related

CoreBluetooth writeValue:forDescriptor: issue

My CoreBluetooth application need to enable the "indication bit" in Client Characteristic Configuration descriptors. Here is what I did:
Start to scan
Start to connect to the device
Call discoverServices
Call discoverCharacteristics inside the callback
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
Call discoverDescriptorsForCharacteristic inside callback
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
Inside callback
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
I called:
if ( [[descriptor.UUID representativeString] isEqualToString:#"2902" ] )
{
const unsigned char raw_data[] = {0x02};
NSData *myData = [NSData dataWithBytes: raw_data length: 2];
[self.cBCP writeValue:myData forDescriptor:descriptor];
}
But My app crashes in writeVale: . The error message in console is :
Cannot write Client Characteristic Configuration descriptors using
this method!
Any idea? Thanks
Pretty old question, but since it wasn't answered, seems like if the method setNotifyValue(_:for:) will handle that for you, it depends on the charcateristics properties below:
Notify only: Notifications will be enabled.
Indicate only: Indications will be enabled.
Indicate & Notify: ONLY Notifications will be enabled.
So if you need to enable indications, the characteristic must only have the indicate property, and notify should be removed.
I guess the main reasoning behind that is indications are much slower, so iOS will always prefer the fastest possible option unless it's a requirement to indicate.
Read more on the Apple docs
The problem is that you cannot use the writeValue:forDescriptor: method to write the value of a Client Configuration Descriptor (UUID = 2902) as you did.
Instead, you should use the setNotifyValue:forCharacteristic: method of the CBPeripheral class to configure client indications or notifications of a characteristic’s value on a server.

How to know if data is ready

I am using RestKit Framework to parse JSON data coming from a web service. Once I send the request URL the data will be downloaded automatically and will be available in one of the delegate methods of RestKit . I am writing this as a re-usable wrapper class, so that I create an instance of this class wherever required and pass only the URL to download and rest of the process will be done by the class. Now, I have a problem, how the instance will know that the data is available to use after download ? How can i achieve that ? NSNotification or delegation ? Any coding examples or suggestions might help. Thanks in advance.
I found that the most convenient way to handle the callback in RestKit was to use the completion blocks. You can pass around this completion block to achieve what you are trying to do.
Here is an example of how you can create a completion block and pass it around.
-(void)startRequest {
RKRequestDidLoadResponseBlock block = ^(RKResponse *response) {
//your completion code
};
[self sendRequestWithCompletionBlock:block];
}
-(void)sendRequestWithCompletionBlock:(RKRequestDidLoadResponseBlock)completionBlock {
RKRequest *request = [RKRequest requestWithURL:[NSURL URLWithString:#"www.google.com"]];
//configure request;
request.onDidLoadResponse = completionBlock;
}

How to resolved Multiple Address in Bonjour based ios application?

I am trying to Implement Banjour based application in ios. I implement success fully also sending and receiving data to one iphone to another iphone.
After browsing the services all other device in the work. and display in to the Table.
Now i want to select some devices in the table view, and send data to the selected devices
For that i created only one socket in each device.
CFSocketContext socketCtxt = {0, self, NULL, NULL, NULL};
witap_socket = CFSocketCreate(kCFAllocatorDefault, PF_INET6, SOCK_STREAM, IPPROTO_TCP, kCFSocketAcceptCallBack, (CFSocketCallBack)&TCPServerAcceptCallBack, &socketCtxt);
if (witap_socket != NULL)
{
protocolFamily = PF_INET6;
}
else
{
witap_socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketAcceptCallBack, (CFSocketCallBack)&TCPServerAcceptCallBack, &socketCtxt);
if (witap_socket != NULL)
{
protocolFamily = PF_INET;
}
}
now i want to send data to the selected devices. for that I stored selected NSNetService(ie devices) another NSMutableArray. When used Click the send button particular Action will invoked.
-(void)SendActionFunction
{
for(int idx=0;idx<[selectedSer count];idx++)
{
NSNetService *service = [self.selectedSer objectAtIndex:idx];
NSLog(#"service......%#",[service name]);
self.currentResolve = [self.selectedSer objectAtIndex:idx];
[self.currentResolve setDelegate:self];
[self.currentResolve resolveWithTimeout:0.0];
}
}
if i am trying to Resolve address for each device(above code). It will resolve only for first device. and getting error
(Error code=-72003]
one more problem if i resolved address for a device it automatically remove from Tableview.
So my doubts are:
Why the selected device revoved?
Now i create TCP based socket, How to add destination address to send data?
Is it possible to send data from single socket to multiple destination?
As per Apple's definition, A CFSocket is a communications channel implemented with a BSD socket.
You have established a socket connection between the devices. But for sending and receiving data, you must make use of NSStreams. Documentation can be found here
I see you are using Apple's sample code Witap as the reference.
For sending and receiving the data, use NSStreamDelegate also.
What about resolve and send datas 1 device per 1 device ? Sounds easier :D
BTW, there is a really nice socket library I used for a project :
https://github.com/robbiehanson/CocoaAsyncSocket

Need some help accessing JSON Data iPhone

Disclaimer: I'm new to JSON.
I have a website that offers up it's Data in JSON format and I'm in the process of building an iPhone App to access that data. The problem I have is not actually with the app itself but rather the syntax to access some of the JSON data.
I don't have any issue accessing the data in the Post [ ] Section, however I want to access Attachments > Images > wptouch-new-thumbnail > url
I know you usually would access the data with a dot syntax but with everything I have tried I have been unable to select anything outside of the Post[] section.
it's pretty simple I take what I get from the server through posts and add them to NSStrings or UIImage in the case of the images for use in a UITableView.
I have all of that working however I can't seem to access anything under attachments. I tried to make a different NSDictionary for attachments but that did not work.
Again remember I'm very new to JSON / Accessing data within it.
Any help would be appreciated!
Make NSMutableData as jsonMutableData instead of NSMutableString.
in connection dedreceiveresponse, initialize jsonMutableData then,
//Json Connection
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[jsonMutableData appendData:partialData];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *jsonData = [[NSString alloc] initWithData:jsonMutableData encoding:NSUTF8StringEncoding];
NSDictionary *filesJSON = [jsonData JSONValue];
NSArray *files = [filesJSON objectForKey:#"posts"];
//further code

Unable to receive data sent using NSStream objects

In my app I doing something very similar to what is done in the WiTap project. I use Bonjour to discover peers and then send data over the socket to perform an initial handshake.
I'm able to see the data being sent OTA using Cocoa Packet Analyzer. But the stream: handleEvent: function is never called on the receiving peer side.
What I am able to see is:
Sometimes, when the peer that sent the data exits, the receiver peer seems to get the data.
Sometimes I am able to see an NSStreamEventErrorOccurred error in the handler function.
I'm unable to see any noticeable pattern on when the above behavior occurs.
Here is a bit of the code that might be helpful.
PacketSender and PacketReceiver objects are singletons.
I have verified multiple times that the correct (and the only) instance of these objects are set as delegates while debugging:
if (![netService getInputStream:&_inStream outputStream:&_outStream])
{
[Utilities showAlert:#"Failed connecting to server"];
return BM_ERROR_NETSERVICE_STREAM_FAIL;
}
if(!sharedProtocolManager.mPacketSender)
{
sharedProtocolManager.mPacketSender = [PacketSender sharedSender];
}
if(!sharedProtocolManager.mPacketReceiver)
{
sharedProtocolManager.mPacketReceiver = [PacketReceiver sharedReceiver];
}
if(!sharedProtocolManager.mPacketSender || !sharedProtocolManager.mPacketReceiver)
{
return BM_ERROR_FAIL;
}
[PacketReceiver setupInStream:_inStream];
[PacketSender setupOutStream:_outStream];
}
Inside the PacketReceiver setupInStream: function I have:
if (sharedPacketReceiver->mInStream != inStream)
{
[sharedPacketReceiver->mInStream release];
sharedPacketReceiver->mInStream = [inStream retain];
}
sharedPacketReceiver->mInStream.delegate = sharedPacketReceiver;
Any answers or even suggestions on ways to debug this further would be greatly appreciated.
Thanks!