Advertising

Google killing XMPP federation with their Google Hangouts?

According to the Ars Technica article on Hangouts, we can expect Google to drop support for XMPP federation.

We should apparently be happy that Google is not dropping XMPP client-to-server connections.

The instant messaging space is apparently turning into a duopoly of Microsoft's Skype and Google's Hangouts with everyone else shoved to the sidelines. I'm not counting Facebook Chat as a serious alternative, and iMessage is not intended as an instant messaging service.

I hopefully don't have to point out how much this frustrates and annoys me. Google is turning out to be worse than Microsoft ever was: they're actively backpedaling on their past promises. They're backstabbing the "open". Scratch that -- they're throwing a stake through open's heart, ripping it in pieces, then gorging on its still beating remains. Instead of reading RSS through Reader, we're supposed to read custom posts via the closed and locked down Google+. They are killing iGoogle. They're basically killing the open web and open Internet, while at the same time paying lip service to open.

Android, which is just-enough-Linux-but-not-really. Rich authorship markup, which requires two-way linking to Google+ instead of using the semantic web techniques.

I'll keep on looking for ways to back out of Google ecosystem as much as possible. What's next -- Gmail that can't send emails out?


rest of the post
About me

Dokumentacija o mrežnom protokolu i datotečnom formatu za fiskalnu blagajnu

Dokumentacija se, zanimljivo, ne nalazi na FINAinom webu o fiskalizaciji, nego na webu porezne uprave.

Zato jer, je li, logično je da se koristi PKI arhitektura FINAe i podnose zahtjevi FINAi i zatim sve submita poreznoj upravi.

Dakle, file format za XML datoteku, postupak potpisivanja (hura, signing) i network protokol. Hura - here's to reading massive amounts of boring stuff! Hura za nove poreze, hura za FINA-u i hura za vrle nam ministre...


rest of the post

Overriding HTTP user agent for calls to -initWithContentsOfURL:

Perhaps you need to override the HTTP user agent whenever you call -initWithContentsOfURL: from classes such as NSString, NSDictionary or NSArray, or one of this method's convenience wrappers such as +stringWithContentsOfURL:, +dictionaryWithContentsOfURL: or +arrayWithContentsOfURL:. So let's consider how this can be accomplished under iOS.

From what I can see, there is no easy and "clean" way apart from adding a category on the classes where you need to support this and writing your own implementation of -initWithContentsOfURL: and convenience functions (with a slightly different name, of course). These implementations would use NSURLConnection's +sendSynchronousRequest:returningResponse:error:. Of course, as with -initWithContentsOfURL: you'd use this replacement method in a background thread to maintain UI responsiveness.

You'd have to write a reimplementation of -initWithContentsOfURL: because the first place you can change this is NSURLRequest, or more specifically, its mutable variant NSMutableURLRequest, using the -setValue:forHTTPHeaderField:. But, if you have tons of code, you probably can't easily change it to use the new method.

So I dug in and, with a few smart tricks (such as feeding a broken non-NSURL as a NSURL to figure out which methods get called, then implementing them as necessary), I figured out which of several ways for fetching web content is actually used in NSString's implementation of -initWithContentsOfURL:. These could have been NSURLConnection or some low level messing with CFNetwork.

It turned out not to matter since NSURLRequest is generated out of the NSURL passed to the method. Customizing the user agent turned out to be just a matter of taking all NSURLRequests, forcing them to become mutable copies in form of instances of NSMutableURLRequest during the initializer and setting the user agent at that time. Specific initializer appearing in iOS implementation used in iOS 5 Simulator that ships with Xcode 4.2.1 appears to be -initWithURL:cachePolicy:timeoutInterval:.

It's an enormous hack, but I decided to simply swizzle this method out. Swizzling NSURLConnection's class method +sendSynchronousRequest:returningResponse:error: did not appear to work - the original method still got called despite my best efforts to figure out what went wrong with swizzling, so I gave up on it. If you can see a mistake in my class swizzling code, please tell me about it in the comments section below.

I definitely have no idea whether or not your app will be rejected for this, but from what I know, method swizzling is not illegal.

//  NSURLRequest+UserAgentFix.m

#define YOUR_USER_AGENT @"Your User Agent"
#import "NSURLRequest+UserAgentFix.h"
#import "NSObject+ISSwizzling.h"
@implementation NSURLRequest (UserAgentFix)
+(void)load
{
    [self swizzleMethod:@selector(initWithURL:cachePolicy:timeoutInterval:)
             withMethod:@selector(initWithURL2:cachePolicy:timeoutInterval:)];
}
-(id)initWithURL2:(NSURL *)URL cachePolicy:(NSURLRequestCachePolicy)cachePolicy timeoutInterval:(NSTimeInterval)timeoutInterval
{
    self = [self initWithURL2:URL cachePolicy:cachePolicy timeoutInterval:timeoutInterval];
    
    if(!self)
        return nil;
    
    if([self class] == [NSURLRequest class])
        self = [self mutableCopy];
    
    if([self class] == [NSMutableURLRequest class])
    {
        NSMutableURLRequest * req = self;
        [req setValue:YOUR_USER_AGENT forHTTPHeaderField:@"User-Agent"];
    }
    
    return self;
}
@end

// NSURLRequest+UserAgentFix.h
#import 

@interface NSURLRequest (UserAgentFix)

@end

// NSObject+ISSwizzling.h
#import 

@interface NSObject (ISSwizzling)
+ (BOOL)swizzleMethod:(SEL)origSelector withMethod:(SEL)newSelector;
+ (BOOL)swizzleClassMethod:(SEL)origSelector withMethod:(SEL)newSelector;

@end

// NSObject+ISSwizzling.m
#import 
#import "NSObject+ISSwizzling.h"

@implementation NSObject (ISSwizzling)
+ (BOOL)swizzleMethod:(SEL)origSelector withMethod:(SEL)newSelector
{
    Method origMethod = class_getInstanceMethod(self, origSelector);
    Method newMethod = class_getInstanceMethod(self, newSelector);
    
    if (origMethod && newMethod) {
        if (class_addMethod(self, origSelector, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) {
            class_replaceMethod(self, newSelector, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
        } else {
            method_exchangeImplementations(origMethod, newMethod);
        }
        return YES;
    }
    return NO;
}
+ (BOOL)swizzleClassMethod:(SEL)origSelector withMethod:(SEL)newSelector
{
    Method origMethod = class_getClassMethod(self, origSelector);
    Method newMethod = class_getClassMethod(self, newSelector);
    
    Class class = object_getClass((id)self);

    if (origMethod && newMethod) {
        if (class_addMethod(class, origSelector, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) {
            class_replaceMethod(class, newSelector, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
        } else {
            method_exchangeImplementations(origMethod, newMethod);
        }
        return YES;
    }
    return NO;
}

@end

Tested on iOS 5 Simulator with NSString's +stringWithContentsOfURL:.


rest of the post

Simple multiuser chat for POSIX systems

Here's a little multiuser chat server written for various POSIX-compatible operating systems. Written and tested on Mac OS X 10.6, but it should work on your favorite Linux, too.

Placed in public domain, use it for whatever you want (since it's so simple). 177 lines of pure C powah, dood.

Code follows after the break. server.c:

#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define SLOTCOUNT 300

int listener = 0;
int slots[SLOTCOUNT] = {0};
int maxslot = 0;
int usage(char* call)
{
  char* fn = strrchr(call, '/')+1;
  if(!fn)
    fn = call;
  printf("usage: %s port\n", fn);
  return 1;
}

void broadcast_message(int sender, char* msg)
{
  int i;
  for(i = 0; i < SLOTCOUNT; i++)
  {
    if(!slots[i])
      continue;
    if(i == sender)
      continue;

    send(i, msg, strlen(msg), 0);
  }

  if(sender != 0)
    printf("%s", msg);
}

int work()
{
  maxslot = listener;
  do
  {
    fd_set set;
    int i;

    FD_ZERO(&set);

    FD_SET(1,        &set);
    FD_SET(listener, &set);
    for(i=0; i < SLOTCOUNT; i++)
    {
      if(slots[i])
      {
        FD_SET(slots[i], &set);
      }
    }

    int koliko = select(maxslot+1, &set, NULL, NULL, NULL);
    if(koliko==-1)
      err(5, "select()");
    
    if(FD_ISSET(1, &set))
    {

      int size;
      if(ioctl(1, FIONREAD, &size) != -1){
        char *buf;

    //    printf("Reading %d bytes...\n", size);
        buf = malloc(size+1);
        read(1, buf, size);
        buf[size] = 0;
    //    printf("Received %s\n", buf);

        broadcast_message(0, buf);

        free(buf);
      }
      else
        err(7, "ioctl() stdio");

    }
    if(FD_ISSET(listener, &set))
    {
      int accepted = accept(listener, NULL, NULL);
      if(accepted == -1)
        err(6, "accept()");

      slots[accepted] = accepted;
      if(accepted > maxslot)
        maxslot = accepted;
    }
  
    for(i = 0; i < SLOTCOUNT; i++)
    {
      if(slots[i] && FD_ISSET(slots[i], &set))
      {
    //    printf("Received on %d\n", i);


        int size;


        if(ioctl(i, FIONREAD, &size) != -1){

          if(size > 0)
          {
            char *buf;

    //        printf("Reading %d bytes...\n", size);
            buf = malloc(size+1);
            read(i, buf, size);
            buf[size] = 0;
    //        printf("Received %s\n", buf);
            
            broadcast_message(i, buf);

            free(buf);
          }
          else
          {
            shutdown(i, SHUT_RDWR);
            close(i);

            slots[i] = 0;

    //        printf("Disconnect on %d\n", i);
          }
        }
        else
          err(8, "ioctl() net");


      }
    }
    
  } while(1);
  return 0;
}


int main(int argc, char** argv)
{
  if(argc < 2)
    return usage(argv[0]);

  if((listener = socket(PF_INET, SOCK_STREAM, 0))==-1)
    err(1, "socket()");
  
  int one=1;
  setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
  
  struct sockaddr_in socketAddress;
  memset(&socketAddress, 0, sizeof(socketAddress));
  socketAddress.sin_len = sizeof(socketAddress);
  socketAddress.sin_family = AF_INET;                   // Address family (IPv4 vs IPv6)
  socketAddress.sin_port = htons(atoi(argv[1]));        // If we passed 0, the actual port would get assigned automatically by kernel and we'd have to retrieve it. Also, we use network byte order for 16bit numbers here by using htons
  socketAddress.sin_addr.s_addr = htonl(INADDR_ANY);    // We must use "network byte order" format (big-endian) for the 32bit value here by using htonl

  printf("Listener: %d\n", listener);
  if(bind(listener, (struct sockaddr*) &socketAddress, sizeof(socketAddress))==-1)
    err(2, "bind()");

  if(listen(listener, 1) == -1)
    err(3, "listen()");

  return work();

}

Makefile:

CFLAGS=-g3
LDFLAGS=-g3

all: server

server: server.o
  gcc server.o $(LDFLAGS) -o server

clean:
  -rm server server.o

Note, in Makefiles, instead of two spaces, use tabs. You need to.

Try it out:

make
./server 1337

And on a few other terminals (or other machines):

telnet localhost 1337

Works over the network, too, of course.

Nota bene, you will probably need to install telnet on your Linux machine. Also, telnet does not come with latest Windows editions (Vista and 7); you will need to use putty over there.


rest of the post