public static byte[] Write(ContentCodeBag bag, ContentNode node)
        {
            MemoryStream stream = new MemoryStream ();
            BinaryWriter writer = new BinaryWriter (stream);
            Write (bag, node, writer);
            writer.Flush ();

            byte [] buf = stream.GetBuffer ();
            long len = stream.Length;
            writer.Close ();

            byte [] ret = new byte [len];
            Array.Copy (buf, ret, len);
            return ret;
        }
        internal static ServerInfo FromNode(ContentNode node)
        {
            ServerInfo info = new ServerInfo ();

            if (node.Name != "dmap.serverinforesponse")
                return null;

            foreach (ContentNode child in (node.Value as ContentNode [])) {
                switch (child.Name) {
                case "dmap.itemname":
                    info.Name = (string) child.Value;
                    break;
                case "dmap.authenticationmethod":
                    info.AuthenticationMethod = (AuthenticationMethod) child.Value;
                    break;
                case "dmap.supportsupdate":
                    info.SupportsUpdate = (byte) child.Value == 1;
                    break;
                }
            }

            return info;
        }
예제 #3
0
        public void DownloadPhoto(Photo photo, string dest)
        {
/*            BinaryWriter writer = new BinaryWriter (File.Open (dest, FileMode.Create));
 *                      MemoryStream data = new MemoryStream ();
 *          try {
 *              long len;
 *              using (BinaryReader reader = new BinaryReader (StreamPhoto (photo, out len))) {
 *                  int count = 0;
 *                  byte [] buf = new byte [chunk_length];
 *
 *                                      // Skip the header
 *                                      //count = reader.Read (buf,0,89);
 *
 *                                      //if (count < 89)
 *                                      //	count+=reader.Read (buf,0,89-count);
 *
 *                                      while (true) {
 *                  buf = reader.ReadBytes (8192);
 *                  if (buf.Length == 0)
 *                      break;
 *
 *                  data.Write (buf, 0, buf.Length);
 *                                      //Console.Write (buf.);
 *                                      }
 *
 */
/*                    do {
 *                      count = reader.Read (buf, 0, chunk_length);
 *                      writer.Write (buf, 0, count);
 *                                              data.Write (buf, 0, count);
 *                  } while (count != 0);
 */
            /*data.Flush ();
             *
             * ContentNode node = ContentParser.Parse (client.Bag, data.GetBuffer ());
             * node.Dump ();
             * reader.Close ();
             *
             *  }
             * } finally {
             * data.Close ();
             *
             *  writer.Close ();
             * }*/
            // maybe use FetchResponse to get a stream and feed it to pixbuf?
            byte [] photos_data = client.Fetcher.Fetch(String.Format("/databases/{0}/items", id),
                                                       String.Format("meta=dpap.thumb,dpap.filedata&query=('dmap.itemid:{0}')", photo.Id));
            ContentNode node = ContentParser.Parse(client.Bag, photos_data);

            // DEBUG
            Console.WriteLine("About to dump the photo!");
            node.Dump();
            ContentNode filedata_node = node.GetChild("dpap.filedata");

            Console.WriteLine("Photo starts at index " + filedata_node.Value);
            BinaryWriter writer = new BinaryWriter(File.Open(dest, FileMode.Create));

            int count = 0;
            int off   = System.Int32.Parse(filedata_node.Value.ToString());

            byte []      photo_buf;
            MemoryStream data = new MemoryStream();

            writer.Write(photos_data, (int)off, (int)photos_data.Length - off);
            data.Position = 0;
            //	Gdk.Pixbuf pb = new Gdk.Pixbuf (data);
            data.Close();
            Console.Write("Written " + count + " out of " + (photos_data.Length - off));
        }
예제 #4
0
        private void RefreshAlbums(string revquery)
        {
            byte [] albums_data;

            try {
                albums_data = client.Fetcher.Fetch(String.Format("/databases/{0}/containers", id), "meta=dpap.aspectratio,dmap.itemid,dmap.itemname,dpap.imagefilename,dpap.imagefilesize,dpap.creationdate,dpap.imagepixelwidth,dpap.imagepixelheight,dpap.imageformat,dpap.imagerating,dpap.imagecomments,dpap.imagelargefilesize&type=photo");
            } catch (WebException) {
                return;
            }

            ContentNode albums_node = ContentParser.Parse(client.Bag, albums_data);

            // DEBUG data
            albums_node.Dump();
            Console.WriteLine("after dump!");

            if (IsUpdateResponse(albums_node))
            {
                return;
            }

            // handle album additions/changes
            ArrayList plids = new ArrayList();

            if (albums_node.GetChild("dmap.listing") == null)
            {
                return;
            }

            foreach (ContentNode albumNode in (ContentNode [])albums_node.GetChild("dmap.listing").Value)
            {
                // DEBUG
                Console.WriteLine("foreach loop");
                Album pl = Album.FromNode(albumNode);
                if (pl != null)
                {
                    plids.Add(pl.Id);
                    Album existing = LookupAlbumById(pl.Id);

                    if (existing == null)
                    {
                        AddAlbum(pl);
                    }
                    else
                    {
                        existing.Update(pl);
                    }
                }
            }
            // DEBUG
            Console.WriteLine("delete albums that don't exist");
            // delete albums that no longer exist
            foreach (Album pl in new List <Album> (albums))
            {
                if (!plids.Contains(pl.Id))
                {
                    RemoveAlbum(pl);
                }
            }

            plids = null;
            // DEBUG
            Console.WriteLine("Add/remove photos in the albums");
            // add/remove photos in the albums
            foreach (Album pl in albums)
            {
                byte [] album_photos_data = client.Fetcher.Fetch(String.Format("/databases/{0}/containers/{1}/items",
                                                                               id, pl.Id), "meta=dpap.aspectratio,dmap.itemid,dmap.itemname,dpap.imagefilename,dpap.imagefilesize,dpap.creationdate,dpap.imagepixelwidth,dpap.imagepixelheight,dpap.imageformat,dpap.imagerating,dpap.imagecomments,dpap.imagelargefilesize&type=photo");
                ContentNode album_photos_node = ContentParser.Parse(client.Bag, album_photos_data);

                if (IsUpdateResponse(album_photos_node))
                {
                    return;
                }

                if ((byte)album_photos_node.GetChild("dmap.updatetype").Value == 1)
                {
                    // handle album photo deletions
                    ContentNode delete_list = album_photos_node.GetChild("dmap.deletedidlisting");

                    if (delete_list != null)
                    {
                        foreach (ContentNode deleted in (ContentNode [])delete_list.Value)
                        {
                            int index = pl.LookupIndexByContainerId((int)deleted.Value);

                            if (index < 0)
                            {
                                continue;
                            }

                            pl.RemoveAt(index);
                        }
                    }
                }

                // add new photos, or reorder existing ones

                int plindex = 0;
                foreach (ContentNode pl_photo_node in (ContentNode [])album_photos_node.GetChild("dmap.listing").Value)
                {
                    Photo plphoto      = null;
                    int   container_id = 0;
                    Photo.FromAlbumNode(this, pl_photo_node, out plphoto, out container_id);

                    if (pl [plindex] != null && pl.GetContainerId(plindex) != container_id)
                    {
                        pl.RemoveAt(plindex);
                        pl.InsertPhoto(plindex, plphoto, container_id);
                    }
                    else if (pl [plindex] == null)
                    {
                        pl.InsertPhoto(plindex, plphoto, container_id);
                    }

                    plindex++;
                }
            }
        }
예제 #5
0
 private bool IsUpdateResponse(ContentNode node)
 {
     return(node.Name == "dmap.updateresponse");
 }
예제 #6
0
        internal Database(Client client, ContentNode dbNode) : this()
        {
            this.client = client;

            Parse(dbNode);
        }
 private bool IsUpdateResponse(ContentNode node)
 {
     return node.Name == "dmap.updateresponse";
 }
예제 #8
0
 public void WriteResponse(Socket client, ContentNode node)
 {
     WriteResponse (client, HttpStatusCode.OK,
                    ContentWriter.Write (ContentCodeBag.Default, node));
 }
        public static ContentNode Parse(ContentCodeBag bag, byte [] buffer, string root,
                                         ref int offset)
        {
            ContentNode node = new ContentNode ();
            int num = IPAddress.NetworkToHostOrder (BitConverter.ToInt32 (buffer, offset));
            ContentCode code;
            // This is a fix for iPhoto '08 which gives wrong content-type for dpap.databasecontainers (aply)
            if (num == 1634757753) {
                code = new ContentCode ();
                code.Name = "dpap.databasecontainers";
                code.Type = ContentType.Container;
            }
            else
                code = bag.Lookup (num);

            if (code.Name.Equals ("dpap.filedata"))
                code.Type = ContentType.FileData;

            if (code.Equals (ContentCode.Zero)) {
                // probably a buggy server.  fallback to our internal code bag
                Console.WriteLine ("fallback to internal code bag");
                Console.WriteLine ("Code number: "+num);
                throw new Exception ("Content code not found!");
            }

            int length = IPAddress.NetworkToHostOrder (BitConverter.ToInt32 (buffer, offset + 4));

            if (code.Equals (ContentCode.Zero)) {
                throw new ContentException (String.Format ("Failed to find content code for '{0}'.  Data length is {1}",
                                                           ContentCodeBag.GetStringFormat (num), length));
            }

            node.Name = code.Name;

            Console.WriteLine ("name = " + node.Name + "Code=" +code.Type.ToString () + " num=" +num);

            switch (code.Type) {
                case ContentType.Char:
                    node.Value = (byte) buffer [offset + 8];
                    break;
                case ContentType.Short:
                    node.Value = IPAddress.NetworkToHostOrder (BitConverter.ToInt16 (buffer, offset + 8));
                    break;
                case ContentType.SignedLong:
                case ContentType.Long:
                    node.Value = IPAddress.NetworkToHostOrder (BitConverter.ToInt32 (buffer, offset + 8));
                    break;
                case ContentType.LongLong:
                    node.Value = IPAddress.NetworkToHostOrder (BitConverter.ToInt64 (buffer, offset + 8));
                    break;
                case ContentType.String:
                    node.Value = Encoding.UTF8.GetString (buffer, offset + 8, length);
                    break;
                case ContentType.Date:
                    node.Value = Utility.ToDateTime (IPAddress.NetworkToHostOrder (BitConverter.ToInt32 (buffer, offset + 8)));
                    break;
                case ContentType.Version:
                    int major = IPAddress.NetworkToHostOrder (BitConverter.ToInt16 (buffer, offset + 8));
                    int minor = (int) buffer [offset + 10];
                    int micro = (int) buffer [offset + 11];

                    node.Value = new Version (major, minor, micro);
                    break;
                case ContentType.Container:
                    node.Value = ParseChildren (bag, buffer, offset + 8, length);
                    break;
                case ContentType.FileData:
                    node.Value = offset+8;
                    break;
                default:
                    throw new ContentException (String.Format ("Unknown content type '{0}' for '{1}'",
                                                               code.Type, code.Name));
            }

            offset += length + 8;

            if (root != null) {
                ContentNode root_node = node.GetChild (root);

                if (root_node == null)
                    throw new ContentException (String.Format ("Could not find root node '{0}'", root));

                return root_node;
            } else
                return node;
        }
예제 #10
0
        internal static Album FromNode(ContentNode node)
        {
            Album pl = new Album ();

            foreach (ContentNode child in (ContentNode []) node.Value) {
                switch (child.Name) {
                case  "dpap.baseplaylist":
                    return null;
                case "dmap.itemid":
                    pl.Id = (int) child.Value;
                    break;
                case "dmap.itemname":
                    pl.Name = (string) child.Value;
                    break;
                default:
                    break;
                }
            }

            return pl;
        }
예제 #11
0
        internal bool OnHandleRequest(Socket client, string username, string path, NameValueCollection query, int range)
        {
            string photoQuery;

            if (query ["query"] != null)
            {
                photoQuery = query ["query"];
            }
            else
            {
                photoQuery = "";
            }

            int session = 0;

            if (query ["session-id"] != null)
            {
                session = Int32.Parse(query ["session-id"]);
            }

/*            if (!sessions.ContainsKey (session) && path != "/server-info" && path != "/content-codes" &&
 *              path != "/login") {
 *              ws.WriteResponse (client, HttpStatusCode.Forbidden, "invalid session id");
 *              return true;
 *          }
 */
            if (session != 0)
            {
                sessions [session].LastActionTime = DateTime.Now;
            }

            int clientRev = 0;

            if (query ["revision-number"] != null)
            {
                clientRev = Int32.Parse(query ["revision-number"]);
            }

            int delta = 0;

            if (query ["delta"] != null)
            {
                delta = Int32.Parse(query ["delta"]);
            }
            // DEBUG data
            Console.WriteLine("Before returning resources for path " + path + ", meta " + query ["meta"] + " query " + photoQuery);
            if (dbItemsRegex.IsMatch(path))              //&& photoQuery.Length==0
            {
                Console.WriteLine("\tThis is a database/items request!");
            }

            if (path == "/server-info")
            {
                ws.WriteResponse(client, GetServerInfoNode());
            }
            else if (path == "/content-codes")
            {
                ws.WriteResponse(client, ContentCodeBag.Default.ToNode());
            }
            else if (path == "/login")
            {
                ExpireSessions();

                if (maxUsers > 0 && sessions.Count + 1 > maxUsers)
                {
                    ws.WriteResponse(client, HttpStatusCode.ServiceUnavailable, "too many users");
                    return(true);
                }

                session = random.Next();
                User user = new User(DateTime.Now, (client.RemoteEndPoint as IPEndPoint).Address, username);

                lock (sessions) {
                    sessions [session] = user;
                }

                ws.WriteResponse(client, GetLoginNode(session));
                OnUserLogin(user);
            }
            else if (path == "/logout")
            {
                Console.WriteLine("logout!");
                User user = sessions [session];

                lock (sessions) {
                    sessions.Remove(session);
                }

                ws.WriteResponse(client, HttpStatusCode.OK, new byte [0]);
                OnUserLogout(user);

                return(false);
            }
            else if (path == "/databases")
            {
                Console.WriteLine("path==/databases");
                ws.WriteResponse(client, GetDatabasesNode());
            }
            else if (dbItemsRegex.IsMatch(path) && photoQuery.Length == 0)    //&& !dbPhotoRegex.IsMatch (query ["query"])) {
            {
                Console.WriteLine("dbItemsRegex, query=" + query ["query"] + " meta=" + query ["meta"]);
                int dbid = Int32.Parse(dbItemsRegex.Match(path).Groups [1].Value);

                Database curdb = revmgr.GetDatabase(clientRev, dbid);

                if (curdb == null)
                {
                    ws.WriteResponse(client, HttpStatusCode.BadRequest, "invalid database id");
                    return(true);
                }

                ArrayList deletedIds = new ArrayList();

                if (delta > 0)
                {
                    Database olddb = revmgr.GetDatabase(clientRev - delta, dbid);

                    if (olddb != null)
                    {
                        foreach (Photo photo in olddb.Photos)
                        {
                            if (curdb.LookupPhotoById(photo.Id) == null)
                            {
                                deletedIds.Add(photo.Id);
                            }
                        }
                    }
                }

                ContentNode node = curdb.ToPhotosNode(query ["meta"].Split(','),
                                                      (int [])deletedIds.ToArray(typeof(int)));
                ws.WriteResponse(client, node);
            }
            else if (dbPhotoRegex.IsMatch(photoQuery))
            {
                Console.WriteLine("dbPhotoRegex");
                Console.WriteLine("dbPhotosRegex, query=" + query ["query"] + " meta=" + query ["meta"]);
                string [] photoIds = query ["query"].Split(',');
                Match     match    = dbPhotoRegex0.Match(path);
                int       dbid     = Int32.Parse(match.Groups [1].Value);
                int       photoid  = 0;


                //match = dbPhotoRegex.Match (photoQuery);

                Database db = revmgr.GetDatabase(clientRev, dbid);
                if (db == null)
                {
                    ws.WriteResponse(client, HttpStatusCode.BadRequest, "invalid database id");
                    return(true);
                }
                ArrayList photoNodes = new ArrayList();
                Photo     photo      = db.LookupPhotoById(1);

                foreach (string photoId in photoIds)
                {
                    match   = dbPhotoRegex.Match(photoId);
                    photoid = Int32.Parse(match.Groups [1].Value);
                    photo   = db.LookupPhotoById(photoid);
                    photoNodes.Add(photo.ToFileData(query ["meta"].Contains("dpap.thumb")));
                    // DEBUG
                    //Console.WriteLine ("Requested photo id=" + photoid);
                }

                ArrayList children = new ArrayList();
                children.Add(new ContentNode("dmap.status", 200));
                children.Add(new ContentNode("dmap.updatetype", (byte)0));
                children.Add(new ContentNode("dmap.specifiedtotalcount", 2));
                children.Add(new ContentNode("dmap.returnedcount", 2));
                children.Add(new ContentNode("dmap.listing", photoNodes));
                ContentNode dbsongs = new ContentNode("dpap.databasesongs", children);

                if (photo == null)
                {
                    ws.WriteResponse(client, HttpStatusCode.BadRequest, "invalid photo id");
                    return(true);
                }

                try {
                    try {
                        if (PhotoRequested != null)
                        {
                            PhotoRequested(this, new PhotoRequestedArgs(username,
                                                                        (client.RemoteEndPoint as IPEndPoint).Address,
                                                                        db, photo));
                        }
                    } catch {}

                    if (photo.FileName != null)
                    {
                        // DEBUG
                        //Console.WriteLine ("photo.Filename != null" + query ["meta"].Split (',') [0]);
                        //ContentNode node = photo.ToFileData ();
                        //node.Dump ();

                        ws.WriteResponse(client, dbsongs);
                    }
                    else if (db.Client != null)
                    {
                        Console.WriteLine("db.Client != null");
                        long   photoLength = 0;
                        Stream photoStream = db.StreamPhoto(photo, out photoLength);

                        try {
                            ws.WriteResponseStream(client, photoStream, photoLength);
                        } catch (IOException) {
                            Console.WriteLine("IOException!");
                        }
                    }
                    else
                    {
                        Console.WriteLine("Else - internal error");
                        ws.WriteResponse(client, HttpStatusCode.InternalServerError, "no file");
                    }
                } finally {
                    // commented out because it breaks the connection after sending a hires photo
                    // client.Close()
                }
            }
            else if (dbContainersRegex.IsMatch(path))
            {
                int dbid = Int32.Parse(dbContainersRegex.Match(path).Groups [1].Value);

                Database db = revmgr.GetDatabase(clientRev, dbid);
                if (db == null)
                {
                    ws.WriteResponse(client, HttpStatusCode.BadRequest, "invalid database id");
                    return(true);
                }

                ws.WriteResponse(client, db.ToAlbumsNode());
            }
            else if (dbContainerItemsRegex.IsMatch(path))
            {
                // DEBUG
                Console.WriteLine("ContainerItems ! path=" + path);

                Match match = dbContainerItemsRegex.Match(path);
                int   dbid  = Int32.Parse(match.Groups [1].Value);
                int   plid  = Int32.Parse(match.Groups [2].Value);

                Database curdb = revmgr.GetDatabase(clientRev, dbid);
                if (curdb == null)
                {
                    ws.WriteResponse(client, HttpStatusCode.BadRequest, "invalid database id");
                    return(true);
                }

                Album curpl = curdb.LookupAlbumById(plid);
                if (curdb == null)
                {
                    ws.WriteResponse(client, HttpStatusCode.BadRequest, "invalid playlist id");
                    return(true);
                }
                // DEBUG
                Console.WriteLine("db and album ready!");
                ArrayList deletedIds = new ArrayList();
                if (delta > 0)
                {
                    Database olddb = revmgr.GetDatabase(clientRev - delta, dbid);

                    if (olddb != null)
                    {
                        Album oldpl = olddb.LookupAlbumById(plid);

                        if (oldpl != null)
                        {
                            IList <Photo> oldplPhotos = oldpl.Photos;
                            for (int i = 0; i < oldplPhotos.Count; i++)
                            {
                                int id = oldpl.GetContainerId(i);
                                if (curpl.LookupIndexByContainerId(id) < 0)
                                {
                                    deletedIds.Add(id);
                                }
                            }
                        }
                    }
                }
                Console.WriteLine("About to send response... meta=" + query["meta"]);
                curpl.ToPhotosNode(query ["meta"].Split(',')).Dump();

                ws.WriteResponse(client, curpl.ToPhotosNode(query ["meta"].Split(',')));
                //, (int []) deletedIds.ToArray (typeof (int))));
            }
            else if (path == "/update")
            {
                int retrev;

                lock (revmgr) {
                    // if they have the current revision, wait for a change
                    if (clientRev == revmgr.Current)
                    {
                        Monitor.Wait(revmgr);
                    }

                    retrev = revmgr.Current;
                }

                if (!running)
                {
                    ws.WriteResponse(client, HttpStatusCode.NotFound, "server has been stopped");
                }
                else
                {
                    ws.WriteResponse(client, GetUpdateNode(retrev));
                }
            }
            else
            {
                ws.WriteResponse(client, HttpStatusCode.Forbidden, "GO AWAY");
            }

            return(true);
        }
예제 #12
0
 public void WriteResponse(Socket client, ContentNode node)
 {
     WriteResponse(client, HttpStatusCode.OK,
                   ContentWriter.Write(ContentCodeBag.Default, node));
 }
예제 #13
0
        private int GetCurrentRevision()
        {
            ContentNode rev_node = ContentParser.Parse(bag, fetcher.Fetch("/update"), "dmap.serverrevision");

            return((int)rev_node.Value);
        }
예제 #14
0
 private void ParseSessionId(ContentNode node)
 {
     fetcher.SessionId = (int)node.GetChild("dmap.sessionid").Value;
 }
예제 #15
0
        private void Parse(ContentNode dbNode)
        {
            foreach (ContentNode item in (ContentNode []) dbNode.Value) {

                switch (item.Name) {
                case "dmap.itemid":
                    id = (int) item.Value;
                    break;
                case "dmap.persistentid":
                    persistent_id = (long) item.Value;
                    break;
                case "dmap.itemname":
                    name = (string) item.Value;
                    break;
                default:
                    break;
                }
            }
        }
예제 #16
0
        internal bool OnHandleRequest(Socket client, string username, string path, NameValueCollection query, int range)
        {
            string photoQuery;
            if (query ["query"] != null)
                photoQuery = query ["query"];
            else
                photoQuery = "";

            int session = 0;
            if (query ["session-id"] != null) {
                session = Int32.Parse (query ["session-id"]);
            }

            /*            if (!sessions.ContainsKey (session) && path != "/server-info" && path != "/content-codes" &&
                path != "/login") {
                ws.WriteResponse (client, HttpStatusCode.Forbidden, "invalid session id");
                return true;
            }
            */
            if (session != 0) {
                sessions [session].LastActionTime = DateTime.Now;
            }

            int clientRev = 0;
            if (query ["revision-number"] != null) {
                clientRev = Int32.Parse (query ["revision-number"]);
            }

            int delta = 0;
            if (query ["delta"] != null) {
                delta = Int32.Parse (query ["delta"]);
            }
            // DEBUG data
            Console.WriteLine ("Before returning resources for path " + path + ", meta " + query ["meta"] + " query " + photoQuery);
            if (dbItemsRegex.IsMatch (path)) //&& photoQuery.Length==0
                Console.WriteLine ("\tThis is a database/items request!");

            if (path == "/server-info") {
                ws.WriteResponse (client, GetServerInfoNode ());
            } else if (path == "/content-codes") {
                ws.WriteResponse (client, ContentCodeBag.Default.ToNode ());
            } else if (path == "/login") {
                ExpireSessions ();

                if (maxUsers > 0 && sessions.Count + 1 > maxUsers) {
                    ws.WriteResponse (client, HttpStatusCode.ServiceUnavailable, "too many users");
                    return true;
                }

                session = random.Next ();
                User user = new User (DateTime.Now, (client.RemoteEndPoint as IPEndPoint).Address, username);

                lock (sessions) {
                    sessions [session] = user;
                }

                ws.WriteResponse (client, GetLoginNode (session));
                OnUserLogin (user);
            } else if (path == "/logout") {
                Console.WriteLine("logout!");
                User user = sessions [session];

                lock (sessions) {
                    sessions.Remove (session);
                }

                ws.WriteResponse (client, HttpStatusCode.OK, new byte [0]);
                OnUserLogout (user);

                return false;
            } else if (path == "/databases") {
                Console.WriteLine ("path==/databases");
                ws.WriteResponse (client, GetDatabasesNode ());
            } else if (dbItemsRegex.IsMatch (path) && photoQuery.Length==0 ){ //&& !dbPhotoRegex.IsMatch (query ["query"])) {
                Console.WriteLine ("dbItemsRegex, query=" + query ["query"] + " meta=" + query ["meta"]);
                int dbid = Int32.Parse (dbItemsRegex.Match (path).Groups [1].Value);

                Database curdb = revmgr.GetDatabase (clientRev, dbid);

                if (curdb == null) {
                    ws.WriteResponse (client, HttpStatusCode.BadRequest, "invalid database id");
                    return true;
                }

                ArrayList deletedIds = new ArrayList ();

                if (delta > 0) {
                    Database olddb = revmgr.GetDatabase (clientRev - delta, dbid);

                    if (olddb != null) {
                        foreach (Photo photo in olddb.Photos) {
                            if (curdb.LookupPhotoById (photo.Id) == null)
                                deletedIds.Add (photo.Id);
                        }
                    }
                }

                ContentNode node = curdb.ToPhotosNode (query ["meta"].Split (','),
                                                      (int []) deletedIds.ToArray (typeof (int)));
                ws.WriteResponse (client, node);
            } else if (dbPhotoRegex.IsMatch (photoQuery)) {
                Console.WriteLine ("dbPhotoRegex");
                Console.WriteLine ("dbPhotosRegex, query=" + query ["query"] + " meta=" + query ["meta"]);
                string [] photoIds = query ["query"].Split (',');
                Match match = dbPhotoRegex0.Match (path);
                int dbid = Int32.Parse (match.Groups [1].Value);
                int photoid = 0;

                //match = dbPhotoRegex.Match (photoQuery);

                Database db = revmgr.GetDatabase (clientRev, dbid);
                if (db == null) {
                    ws.WriteResponse (client, HttpStatusCode.BadRequest, "invalid database id");
                    return true;
                }
                ArrayList photoNodes = new ArrayList ();
                Photo photo = db.LookupPhotoById (1);

                foreach (string photoId in photoIds) {
                    match = dbPhotoRegex.Match (photoId);
                    photoid = Int32.Parse (match.Groups [1].Value);
                    photo = db.LookupPhotoById (photoid);
                    photoNodes.Add (photo.ToFileData (query ["meta"].Contains ("dpap.thumb")));
                    // DEBUG
                    //Console.WriteLine ("Requested photo id=" + photoid);
                }

                ArrayList children = new ArrayList ();
                children.Add (new ContentNode ("dmap.status", 200));
                children.Add (new ContentNode ("dmap.updatetype", (byte) 0));
                children.Add (new ContentNode ("dmap.specifiedtotalcount",  2));
                children.Add (new ContentNode ("dmap.returnedcount", 2));
                children.Add (new ContentNode ("dmap.listing", photoNodes));
                ContentNode dbsongs = new ContentNode ("dpap.databasesongs", children);

                if (photo == null) {
                    ws.WriteResponse (client, HttpStatusCode.BadRequest, "invalid photo id");
                    return true;
                }

                try {
                    try {
                        if (PhotoRequested != null)
                            PhotoRequested (this, new PhotoRequestedArgs (username,
                                                                        (client.RemoteEndPoint as IPEndPoint).Address,
                                                                        db, photo));
                    } catch {}

                    if (photo.FileName != null) {
                        // DEBUG
                        //Console.WriteLine ("photo.Filename != null" + query ["meta"].Split (',') [0]);
                        //ContentNode node = photo.ToFileData ();
                        //node.Dump ();

                        ws.WriteResponse (client, dbsongs);

                    } else if (db.Client != null) {
                        Console.WriteLine ("db.Client != null");
                        long photoLength = 0;
                        Stream photoStream = db.StreamPhoto (photo, out photoLength);

                        try {
                            ws.WriteResponseStream (client, photoStream, photoLength);
                        } catch (IOException) {
                            Console.WriteLine("IOException!");
                        }
                    } else {
                        Console.WriteLine ("Else - internal error");
                        ws.WriteResponse (client, HttpStatusCode.InternalServerError, "no file");
                    }
                } finally {
                    // commented out because it breaks the connection after sending a hires photo
                    // client.Close()
                }
            } else if (dbContainersRegex.IsMatch (path)) {
                int dbid = Int32.Parse (dbContainersRegex.Match (path).Groups [1].Value);

                Database db = revmgr.GetDatabase (clientRev, dbid);
                if (db == null) {
                    ws.WriteResponse (client, HttpStatusCode.BadRequest, "invalid database id");
                    return true;
                }

                ws.WriteResponse (client, db.ToAlbumsNode ());
            } else if (dbContainerItemsRegex.IsMatch (path)) {
                // DEBUG
                Console.WriteLine ("ContainerItems ! path=" + path);

                Match match = dbContainerItemsRegex.Match (path);
                int dbid = Int32.Parse (match.Groups [1].Value);
                int plid = Int32.Parse (match.Groups [2].Value);

                Database curdb = revmgr.GetDatabase (clientRev, dbid);
                if (curdb == null) {
                    ws.WriteResponse (client, HttpStatusCode.BadRequest, "invalid database id");
                    return true;
                }

                Album curpl = curdb.LookupAlbumById (plid);
                if (curdb == null) {
                    ws.WriteResponse (client, HttpStatusCode.BadRequest, "invalid playlist id");
                    return true;
                }
                // DEBUG
                Console.WriteLine("db and album ready!");
                ArrayList deletedIds = new ArrayList ();
                if (delta > 0) {
                    Database olddb = revmgr.GetDatabase (clientRev - delta, dbid);

                    if (olddb != null) {
                        Album oldpl = olddb.LookupAlbumById (plid);

                        if (oldpl != null) {
                            IList<Photo> oldplPhotos = oldpl.Photos;
                            for (int i = 0; i < oldplPhotos.Count; i++) {
                                int id = oldpl.GetContainerId (i);
                                if (curpl.LookupIndexByContainerId (id) < 0) {
                                    deletedIds.Add (id);
                                }
                            }
                        }
                    }
                }
                Console.WriteLine("About to send response... meta=" + query["meta"]);
                curpl.ToPhotosNode (query ["meta"].Split (',')).Dump ();

                ws.WriteResponse (client, curpl.ToPhotosNode (query ["meta"].Split (',')));
                //, (int []) deletedIds.ToArray (typeof (int))));
            } else if (path == "/update") {
                int retrev;

                lock (revmgr) {
                    // if they have the current revision, wait for a change
                    if (clientRev == revmgr.Current) {
                        Monitor.Wait (revmgr);
                    }

                    retrev = revmgr.Current;
                }

                if (!running) {
                    ws.WriteResponse (client, HttpStatusCode.NotFound, "server has been stopped");
                } else {
                    ws.WriteResponse (client, GetUpdateNode (retrev));
                }
            } else {
                ws.WriteResponse (client, HttpStatusCode.Forbidden, "GO AWAY");
            }

            return true;
        }
예제 #17
0
        private ContentNode GetDatabasesNode()
        {
            ArrayList databaseNodes = new ArrayList ();

            List<Database> dbs = revmgr.GetRevision (revmgr.Current);
            if (dbs != null) {
                foreach (Database db in revmgr.GetRevision (revmgr.Current)) {
                    databaseNodes.Add (db.ToDatabaseNode ());
                }
            }

            ContentNode node = new ContentNode ("dpap.serverdatabases",
                                                new ContentNode ("dmap.status", 200),
                                                new ContentNode ("dmap.updatetype", (byte) 0),
                                                new ContentNode ("dmap.specifiedtotalcount", databases.Count),
                                                new ContentNode ("dmap.returnedcount", databases.Count),
                                                new ContentNode ("dmap.listing", databaseNodes));

            return node;
        }
예제 #18
0
        public static ContentCodeBag ParseCodes(byte [] buffer)
        {
            ContentCodeBag bag = new ContentCodeBag();

            // add some codes to bootstrap us
            bag.AddCode("mccr", "dmap.contentcodesresponse", ContentType.Container);
            bag.AddCode("mdcl", "dmap.dictionary", ContentType.Container);
            bag.AddCode("mcnm", "dmap.contentcodesnumber", ContentType.Long);
            bag.AddCode("mcna", "dmap.contentcodesname", ContentType.String);
            bag.AddCode("mcty", "dmap.contentcodestype", ContentType.Short);
            bag.AddCode("mstt", "dmap.status", ContentType.Long);

            // some photo-specific codes
            // shouldn't be needed now
            bag.AddCode("ppro", "dpap.protocolversion", ContentType.Long);
            bag.AddCode("pret", "dpap.blah", ContentType.Container);
            bag.AddCode("avdb", "dpap.serverdatabases", ContentType.Container);
            bag.AddCode("aply", "dpap.databasecontainers", ContentType.Container);
            bag.AddCode("abpl", "dpap.baseplaylist", ContentType.Char);
            bag.AddCode("apso", "dpap.playlistsongs", ContentType.Container);
            bag.AddCode("pasp", "dpap.aspectratio", ContentType.String);
            bag.AddCode("adbs", "dpap.databasesongs", ContentType.Container);
            bag.AddCode("picd", "dpap.creationdate", ContentType.Long);
            bag.AddCode("pifs", "dpap.imagefilesize", ContentType.Long);
            bag.AddCode("pwth", "dpap.imagepixelwidth", ContentType.Long);
            bag.AddCode("phgt", "dpap.imagepixelheight", ContentType.Long);
            bag.AddCode("pcmt", "dpap.imagecomments", ContentType.String);
            bag.AddCode("prat", "dpap.imagerating", ContentType.Long);
            bag.AddCode("pimf", "dpap.imagefilename", ContentType.String);
            bag.AddCode("pfmt", "dpap.imageformat", ContentType.String);
            bag.AddCode("plsz", "dpap.imagelargefilesize", ContentType.Long);
            bag.AddCode("pfdt", "dpap.filedata", ContentType.FileData);



            ContentNode node = ContentParser.Parse(bag, buffer);

            foreach (ContentNode dictNode in (node.Value as ContentNode []))
            {
                if (dictNode.Name != "dmap.dictionary")
                {
                    continue;
                }

                ContentCode code = new ContentCode();

                foreach (ContentNode item in (dictNode.Value as ContentNode []))
                {
                    switch (item.Name)
                    {
                    case "dmap.contentcodesnumber":
                        code.Number = (int)item.Value;
                        break;

                    case "dmap.contentcodesname":
                        code.Name = (string)item.Value;
                        break;

                    case "dmap.contentcodestype":
                        code.Type = (ContentType)Enum.ToObject(typeof(ContentType), (short)item.Value);
                        break;
                    }
                }

                bag.codes [code.Number] = code;
            }
            return(bag);
        }
예제 #19
0
        private static void Write(ContentCodeBag bag, ContentNode node, BinaryWriter writer)
        {
            ContentCode code = bag.Lookup(node.Name);

            if (code.Equals(ContentCode.Zero))
            {
                throw new ContentException("Failed to get content code for: " + node.Name);
            }

            writer.Write(IPAddress.HostToNetworkOrder(code.Number));

            switch (code.Type)
            {
            case ContentType.Char:
                writer.Write(IPAddress.HostToNetworkOrder(1));
                writer.Write((byte)node.Value);
                break;

            case ContentType.Short:
                writer.Write(IPAddress.HostToNetworkOrder(2));
                writer.Write(IPAddress.HostToNetworkOrder((short)node.Value));
                break;

            case ContentType.SignedLong:
            case ContentType.Long:
                writer.Write(IPAddress.HostToNetworkOrder(4));
                writer.Write(IPAddress.HostToNetworkOrder((int)node.Value));
                break;

            case ContentType.LongLong:
                writer.Write(IPAddress.HostToNetworkOrder(8));
                writer.Write(IPAddress.HostToNetworkOrder((long)node.Value));
                break;

            case ContentType.String:
                byte [] data = Encoding.UTF8.GetBytes((string)node.Value);
                writer.Write(IPAddress.HostToNetworkOrder(data.Length));
                writer.Write(data);
                break;

            case ContentType.Date:
                writer.Write(IPAddress.HostToNetworkOrder(4));
                writer.Write(IPAddress.HostToNetworkOrder(Utility.FromDateTime((DateTime)node.Value)));
                break;

            case ContentType.Version:
                Version version = (Version)node.Value;
                writer.Write(IPAddress.HostToNetworkOrder(4));

                writer.Write((short)IPAddress.HostToNetworkOrder((short)version.Major));
                writer.Write((byte)version.Minor);
                writer.Write((byte)version.Build);
                break;

            case ContentType.FileData:
                // after "pfdt" we should send the file size and then immediately the file's contents
                // DEBUG
                //Console.WriteLine ("ContentWriter FileData!");
                ContentNode [] nodes = (ContentNode [])node.Value;

                //Console.WriteLine (nodes [0].Value);
                writer.Write(IPAddress.HostToNetworkOrder((int)nodes [0].Value));
                FileInfo info = new FileInfo((string)nodes [1].Value);
                //Console.WriteLine ("reading file " + nodes [1].Value + ", length=" +info.Length);


                FileStream stream = info.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
                int        offset = -1;
                using (BinaryReader reader = new BinaryReader(stream)) {
                    if (offset > 0)
                    {
                        reader.BaseStream.Seek(offset, SeekOrigin.Begin);
                    }

                    long count = 0;
                    long len   = info.Length;
                    while (count < len)
                    {
                        byte [] buf = reader.ReadBytes(Math.Min(8192, (int)len - (int)count));
                        if (buf.Length == 0)
                        {
                            break;
                        }

                        writer.Write(buf);
                        count += buf.Length;
                    }
                }
                break;

            case ContentType.Container:
                MemoryStream child_stream = new MemoryStream();
                BinaryWriter child_writer = new BinaryWriter(child_stream);

                foreach (ContentNode child in (ContentNode [])node.Value)
                {
                    Write(bag, child, child_writer);
                }

                child_writer.Flush();
                byte [] bytes = child_stream.GetBuffer();
                int     len   = (int)child_stream.Length;

                writer.Write(IPAddress.HostToNetworkOrder(len));
                writer.Write(bytes, 0, len);
                child_writer.Close();
                break;

            default:
                Console.Error.WriteLine("Cannot write node of type: " + code.Type);
                break;
            }
        }
예제 #20
0
        public static ContentNode Parse(ContentCodeBag bag, byte [] buffer, string root,
                                        ref int offset)
        {
            ContentNode node = new ContentNode();
            int         num  = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(buffer, offset));
            ContentCode code;

            // This is a fix for iPhoto '08 which gives wrong content-type for dpap.databasecontainers (aply)
            if (num == 1634757753)
            {
                code      = new ContentCode();
                code.Name = "dpap.databasecontainers";
                code.Type = ContentType.Container;
            }
            else
            {
                code = bag.Lookup(num);
            }

            if (code.Name.Equals("dpap.filedata"))
            {
                code.Type = ContentType.FileData;
            }

            if (code.Equals(ContentCode.Zero))
            {
                // probably a buggy server.  fallback to our internal code bag
                Console.WriteLine("fallback to internal code bag");
                Console.WriteLine("Code number: " + num);
                throw new Exception("Content code not found!");
            }

            int length = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(buffer, offset + 4));

            if (code.Equals(ContentCode.Zero))
            {
                throw new ContentException(String.Format("Failed to find content code for '{0}'.  Data length is {1}",
                                                         ContentCodeBag.GetStringFormat(num), length));
            }

            node.Name = code.Name;

            Console.WriteLine("name = " + node.Name + "Code=" + code.Type.ToString() + " num=" + num);

            switch (code.Type)
            {
            case ContentType.Char:
                node.Value = (byte)buffer [offset + 8];
                break;

            case ContentType.Short:
                node.Value = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, offset + 8));
                break;

            case ContentType.SignedLong:
            case ContentType.Long:
                node.Value = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(buffer, offset + 8));
                break;

            case ContentType.LongLong:
                node.Value = IPAddress.NetworkToHostOrder(BitConverter.ToInt64(buffer, offset + 8));
                break;

            case ContentType.String:
                node.Value = Encoding.UTF8.GetString(buffer, offset + 8, length);
                break;

            case ContentType.Date:
                node.Value = Utility.ToDateTime(IPAddress.NetworkToHostOrder(BitConverter.ToInt32(buffer, offset + 8)));
                break;

            case ContentType.Version:
                int major = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, offset + 8));
                int minor = (int)buffer [offset + 10];
                int micro = (int)buffer [offset + 11];

                node.Value = new Version(major, minor, micro);
                break;

            case ContentType.Container:
                node.Value = ParseChildren(bag, buffer, offset + 8, length);
                break;

            case ContentType.FileData:
                node.Value = offset + 8;
                break;

            default:
                throw new ContentException(String.Format("Unknown content type '{0}' for '{1}'",
                                                         code.Type, code.Name));
            }

            offset += length + 8;

            if (root != null)
            {
                ContentNode root_node = node.GetChild(root);

                if (root_node == null)
                {
                    throw new ContentException(String.Format("Could not find root node '{0}'", root));
                }

                return(root_node);
            }
            else
            {
                return(node);
            }
        }
        private static void Write(ContentCodeBag bag, ContentNode node, BinaryWriter writer)
        {
            ContentCode code = bag.Lookup (node.Name);
            if (code.Equals (ContentCode.Zero)) {
                throw new ContentException ("Failed to get content code for: " + node.Name);
            }

            writer.Write (IPAddress.HostToNetworkOrder (code.Number));

            switch (code.Type) {
            case ContentType.Char:
                writer.Write (IPAddress.HostToNetworkOrder (1));
                writer.Write ( (byte) node.Value);
                break;
            case ContentType.Short:
                writer.Write (IPAddress.HostToNetworkOrder (2));
                writer.Write (IPAddress.HostToNetworkOrder ( (short) node.Value));
                break;
            case ContentType.SignedLong:
            case ContentType.Long:
                writer.Write (IPAddress.HostToNetworkOrder (4));
                writer.Write (IPAddress.HostToNetworkOrder ( (int) node.Value));
                break;
            case ContentType.LongLong:
                writer.Write (IPAddress.HostToNetworkOrder (8));
                writer.Write (IPAddress.HostToNetworkOrder ( (long) node.Value));
                break;
            case ContentType.String:
                byte [] data = Encoding.UTF8.GetBytes ( (string) node.Value);
                writer.Write (IPAddress.HostToNetworkOrder (data.Length));
                writer.Write (data);
                break;
            case ContentType.Date:
                writer.Write (IPAddress.HostToNetworkOrder (4));
                writer.Write (IPAddress.HostToNetworkOrder (Utility.FromDateTime ( (DateTime) node.Value)));
                break;
            case ContentType.Version:
                Version version = (Version) node.Value;
                writer.Write (IPAddress.HostToNetworkOrder (4));

                writer.Write ( (short) IPAddress.HostToNetworkOrder ( (short) version.Major));
                writer.Write ( (byte) version.Minor);
                writer.Write ( (byte) version.Build);
                break;
            case ContentType.FileData:
                // after "pfdt" we should send the file size and then immediately the file's contents
                // DEBUG
                //Console.WriteLine ("ContentWriter FileData!");
                ContentNode [] nodes = (ContentNode []) node.Value;

                //Console.WriteLine (nodes [0].Value);
                writer.Write (IPAddress.HostToNetworkOrder ( (int)nodes [0].Value));
                FileInfo info = new FileInfo ( (string)nodes [1].Value);
                //Console.WriteLine ("reading file " + nodes [1].Value + ", length=" +info.Length);

                FileStream stream = info.Open (FileMode.Open, FileAccess.Read, FileShare.Read);
                int offset = -1;
                using (BinaryReader reader = new BinaryReader (stream)) {
                    if (offset > 0) {
                        reader.BaseStream.Seek (offset, SeekOrigin.Begin);
                    }

                    long count = 0;
                    long len = info.Length;
                    while (count < len) {
                        byte [] buf = reader.ReadBytes (Math.Min (8192, (int) len - (int) count));
                        if (buf.Length == 0) {
                            break;
                        }

                        writer.Write (buf);
                        count += buf.Length;
                    }
                }
                break;
            case ContentType.Container:
                MemoryStream child_stream = new MemoryStream ();
                BinaryWriter child_writer = new BinaryWriter (child_stream);

                foreach (ContentNode child in (ContentNode []) node.Value) {
                    Write (bag, child, child_writer);
                }

                child_writer.Flush ();
                byte [] bytes = child_stream.GetBuffer ();
                int len = (int) child_stream.Length;

                writer.Write (IPAddress.HostToNetworkOrder (len));
                writer.Write (bytes, 0, len);
                child_writer.Close ();
                break;
            default:
                Console.Error.WriteLine ("Cannot write node of type: " + code.Type);
                break;
            }
        }
예제 #22
0
        internal Database(Client client, ContentNode dbNode)
            : this()
        {
            this.client = client;

            Parse (dbNode);
        }