/// <summary>
        /// Главниот дел - хендлерот за пакети
        /// </summary>
        /// <param name="packet"></param>
        public void notify(Packet packet)
        {
		
            String type = packet.Type;
            Packet query = packet.getFirstChild("query");
            username = query.getChildValue("username");
            iq.setID(packet.getID());
            iq.Session = packet.Session;
            iq.getChildren().Clear();
            iq.Type = "result";

            reply = new Packet("query");
            reply.setAttribute("xmlns", "jabber:iq:auth");
            reply.Parent = iq;

            user = userIndex.getUser(username);
            if (user == null)
            {
                sendErrorPacket(404, "User not found");
                return;
            }

            if (userIndex.sessionIndex.ContainsValue(user) == true)
            {
                sendErrorPacket(404, "User already Logged In");
                return;
            }
            

            if (type.Equals("get"))
            {
                sendGetPacket();
                return;
            }
            else if (type.Equals("set"))
            {
                session = packet.Session;
					 if (session.Status != Session.SessionStatus.streaming) {
						 sendErrorPacket(400, "Server name does not match");
						 return;
					 }
                resource = query.getChildValue("resource");
                if (resource == null)
                {
                    sendErrorPacket(404, "You must send resource");
                    return;
                }
                handleSetPacket(query);
                return;
            }
        }
        }//update roster
        public void informSubscriber()
        {
            //needs to be checked!
            if ((Server.JabberServer.RosterHashtable[this.user] as UserRoster) != null)
            {
                foreach (object obj in (Server.JabberServer.RosterHashtable[this.user] as UserRoster).subscribers.Keys)
                {
                    Subscriber sub = (Server.JabberServer.RosterHashtable[this.user] as UserRoster).subscribers[obj] as Subscriber;
                    if (sub.subscription.Equals("from") || sub.subscription.Equals("both"))//inform sender of his subscribers status!
                    {
                        JabberID myid = new JabberID(obj.ToString());//other's subscribers id
                        if (myid.Domain.Equals(Server.JabberServer.server_name))//if from this server
                        {
                            //new code!
                           
                            
                            
                            
                            
                            
                            if (Server.JabberServer.getUserIndex().getUser(myid.User).getSessions().Values==null)
                            {
                                // if Server.JabberServer.getUserIndex().getUser(myid.User).getSessions()
                                //user is offline
                                Packet presencePacket = new Packet("presence");
                                presencePacket.From = myid.ToString();
                                presencePacket.To = new JabberID(this.user + "@" + Server.JabberServer.server_name).ToString();
                                presencePacket.setAttribute("type", "unavailable");
                                MessageHandler.deliverPacket(presencePacket);

                            }// if (Server.JabberServer.getUserIndex().getUser(myid.User).getSessions().Values!=null)
                            else
                            {
                                foreach (Object obj2 in (Server.JabberServer.getUserIndex().getUser(myid.User).getSessions().Values))
                                {//for each active session
                                    Session sess = obj2 as Session;
 
                                    Packet presencePacket = new Packet("presence");
                                    presencePacket.From = myid.ToString();
                                    presencePacket.To = new JabberID(this.user + "@" + Server.JabberServer.server_name).ToString();
                                    if (sess.getPresence().isAvailible())
                                    {
                                        presencePacket.setAttribute("type", "available");
                                        if(sess.getPresence().getShow()!=null)
                                            presencePacket.Children.Add(new Packet("show",sess.getPresence().getShow()));
 
                                        
                                        if(sess.getPresence().getStatus()!=null)
                                            presencePacket.Children.Add(new Packet("status",sess.getPresence().getStatus()));


                                        if (sess.getPresence().getPriority() != null)
                                            presencePacket.Children.Add(new Packet("priority", sess.getPresence().getPriority()));
 
                                        //other info may be added!
                                    }
                                    else
                                        presencePacket.setAttribute("type", "unavailable");
                                    MessageHandler.deliverPacket(presencePacket);

                                }//for each active session
                            
                              
                            }

                        }//  if(myid.Domain.Equals(Server.JabberServer.server_name))
                        else
                        {
                            //generate probe for S2S communication!@TODO
                        }
                        
                    }//if (sub.subscription.Equals("from") || sub.subscription.Equals("both"))
                }//foreach (object obj in (Server.JabberServer.RosterHashtable[this.user] as UserRoster).subscribers.Keys)

            }//if ((Server.JabberServer.RosterHashtable[this.user] as UserRoster) != null)


        }
        }//Update subscribers


        public Packet getPacket()
        {
            Packet packet = new Packet("query");
            packet.setAttribute("xmlns", "jabber:iq:roster");
            //works, checked!:
            if ((Server.JabberServer.RosterHashtable[this.user] as UserRoster) != null)
            {
                foreach (object obj in (Server.JabberServer.RosterHashtable[this.user] as UserRoster).items.Values)
                {
                    ((Packet)obj).Parent = packet;
                }
                return packet;
            }
            else return packet;
        }//getPacket
        public void updatePresence(Packet presence)
        {
            String type = presence.Type;
            Session session = presence.Session;
            Presence sessionPresence = session.getPresence();
            String recipient = presence.To;
            JabberID recipientID;
            Boolean isUserSent;//it is not used yet, may be used in S2S comunication

            //packet filling begins
            if (recipient == null)
            {   //directed to server
                //server name
                recipientID = new JabberID(Server.JabberServer.server_name);
                isUserSent = true;
            }
            else
            {
                recipientID = new JabberID(recipient);
                if (user.Equals(recipientID.User))
                {
                    isUserSent = false;
                }
                else
                {
                    isUserSent = true;
                }
            }
            String sender = presence.From;
            JabberID SenderID;
            if (sender == null)
            {
                SenderID = session.JID;
            }
            else
            {
                SenderID = new JabberID(sender);
            }
            //added by marko
            presence.From = SenderID.User + "@" + SenderID.Domain;

            //original line:
            //String subscriber = isUserSent ? recipientID.ToString() : SenderID.ToString();
            String subscriber = recipientID.ToString();

            if (type == null)
            {
                type = "available";
            }
            //packet filling ends


            //packet routing begins
            if (type.Equals("available") || type.Equals("unavailable"))
            {
                //user-managed presence updates are delivered untouched
                if (!recipientID.ToString().Equals(Server.JabberServer.server_name))
                {
                    //may need some work;
                    MessageHandler.deliverPacket(presence);
                    return;
                }


                //Server-managed presence updates are forwarded only to subscribers

                //update the session's presence status

                sessionPresence.Availible = type.Equals("available");
                sessionPresence.Show = presence.getChildValue("show");
                sessionPresence.Status = presence.getChildValue("status");
                String priority = presence.getChildValue("priority");
                sessionPresence.Priority = priority;
                if (priority != null)
                {
                    //some code to set the priority of the session

                    try
                    {
                        session.setPriority(int.Parse(priority));
                    }
                    catch (Exception ex)
                    {
                        JabberServer.output.WriteLine("Error in incoming priority, setting priority to default: 1");
                        session.setPriority(0);
                    }
                }

                //deliver to all users presence subscribers
                updateSubscribers(presence);
                informSubscriber();
                return;
            }

            if (type.Equals("probe"))
            {

                //needed for server to server communication!!!!
                JabberServer.output.WriteLine("Roster: We don't handle probes yet " + presence.ToString());
                return;


            }



            //Marko believes it is checked for exceptions
            //Subscriber sendersSubscriberItem = (Subscriber)subscribers[subscriber];
            Subscriber sendersSubscriberItem = new Subscriber();

            Hashtable Rosters = JabberServer.RosterHashtable;//get reference to rosters


            //prepare sender's roster
            UserRoster senderRoster = Rosters[this.user] as UserRoster;//getting senders roster
            if (senderRoster == null)
            {
                senderRoster = new UserRoster();
                senderRoster.user = this.user;
            }
            if (!Rosters.ContainsKey(this.user))
            {
                Rosters.Add(this.user, senderRoster);
            }

            //prepare recipients roster
            UserRoster recipientRoster = Rosters[recipientID.User] as UserRoster;//getting recipients roster
            if (recipientRoster == null)
            {
                recipientRoster = new UserRoster();
                recipientRoster.user = recipientID.User;
            }
            if (!Rosters.ContainsKey(recipientID.User))
            {
                Rosters.Add(recipientID.User, recipientRoster);
            }

            sendersSubscriberItem = senderRoster.subscribers[subscriber] as Subscriber;//extra

            if (sendersSubscriberItem == null)
            {
                //create subscription item
                sendersSubscriberItem = new Subscriber();
                sendersSubscriberItem.subscription = "none";
                senderRoster.subscribers.Add(recipient, sendersSubscriberItem);
                Packet itempacket = new Packet("item");
                itempacket.setAttribute("jid", subscriber);
                senderRoster.items.Add(subscriber, itempacket);
            }

            //begin subscription managment
            if (type.Equals("subscribe"))
            {
                sendersSubscriberItem.ask = type;//set up subscription status
            }
            else if (type.Equals("subscribed"))//if subscription accepted
            {
                sendersSubscriberItem.ask = null;
                if (sendersSubscriberItem.subscription.Equals("from"))
                {
                    sendersSubscriberItem.subscription = "both";
                }
                else if (sendersSubscriberItem.subscription.Equals("none"))
                {
                    sendersSubscriberItem.subscription = "to";
                }

            }
            else if (type.Equals("unsubscribed"))
            {//sender does not want to give presence updates to recipient
                sendersSubscriberItem.ask = null;

                if (sendersSubscriberItem.subscription.Equals("to"))
                {
                    sendersSubscriberItem.subscription = "none";
                }

                else if (sendersSubscriberItem.subscription.Equals("both"))
                {
                    sendersSubscriberItem.subscription = "from";
                }


                //notify recipient of sender's unavailble status:
                Packet unavailiblePacket = new Packet("presence");
                unavailiblePacket.setFrom(presence.From);
                unavailiblePacket.To = presence.To;
                unavailiblePacket.setAttribute("type", "unavailable");
                MessageHandler.deliverPacket(unavailiblePacket);

            }
            else if (type.Equals("unsubscribe"))
            {//sender no longer interested in recieving presence updates from recipient
                sendersSubscriberItem.ask = null;

                if (sendersSubscriberItem.subscription.Equals("both"))
                {
                    sendersSubscriberItem.subscription = "to";
                }
                else if (sendersSubscriberItem.subscription.Equals("from"))
                {
                    sendersSubscriberItem.subscription = "none";
                }

            }
            //update the corresponding changes in <items> table in sender's record used for delivery
            Packet item = (Packet)senderRoster.items[subscriber];
            if (item != null)
            {
                item.setAttribute("subscription", sendersSubscriberItem.subscription);
                item.setAttribute("ask", sendersSubscriberItem.ask);
                Packet iq = new Packet("iq");
                iq.Type = "set";
                Packet query = new Packet("query");
                query.setAttribute("xmlns", "jabber:iq:roster");
                query.setParent(iq);
                item.setParent(query);
                iq.To = this.user + "@" + Server.JabberServer.server_name;

                //Forward the subscription packet to recipient
                MessageHandler.deliverPacketToAll(user, iq);//may need some correction!
            }

            //processing of recipients roster begins
            if (sendersSubscriberItem.ask == null)
            {
                //the recipient user rosters update!
                Subscriber recipientsSubscriberItem = recipientRoster.subscribers[user + "@" + JabberServer.server_name] as Subscriber;//extra
                if (recipientsSubscriberItem == null)
                {
                    //create subscription item
                    recipientsSubscriberItem = new Subscriber();
                    recipientsSubscriberItem.subscription = "none";
                    recipientRoster.subscribers.Add(user + "@" + JabberServer.server_name, recipientsSubscriberItem);
                }

                //if type is subscribe, changes in this roster are not needed!!!

                if (type.Equals("subscribed"))//if subscription accepted
                {
                    recipientsSubscriberItem.ask = null;
                    if (recipientsSubscriberItem.subscription.Equals("none"))
                    {
                        recipientsSubscriberItem.subscription = "from";
                    }

                    else if (recipientsSubscriberItem.subscription.Equals("to"))
                    {
                        recipientsSubscriberItem.subscription = "both";
                    }

                }
                else if (type.Equals("unsubscribed"))
                {//sender no longer interested in giving presence updates to recipient
                    recipientsSubscriberItem.ask = null;
                    if (recipientsSubscriberItem.subscription.Equals("both"))
                    {
                        recipientsSubscriberItem.subscription = "to";
                    }
                    else if (recipientsSubscriberItem.subscription.Equals("from"))
                    {
                        recipientsSubscriberItem.subscription = "none";
                    }

                }
                else if (type.Equals("unsubscribe"))
                {//sender no longer interested in recieving presence updates from recipient
                    recipientsSubscriberItem.ask = null;
                    if (recipientsSubscriberItem.subscription.Equals("to"))
                    {
                        recipientsSubscriberItem.subscription = "none";
                    }

                    else if (recipientsSubscriberItem.subscription.Equals("both"))
                    {
                        recipientsSubscriberItem.subscription = "from";
                    }

                    //notify sender of unavailble status:
                    Packet unavailiblePacket = new Packet("presence");
                    unavailiblePacket.setFrom(presence.To);
                    unavailiblePacket.To = presence.From;
                    unavailiblePacket.setAttribute("type", "unavailable");
                    MessageHandler.deliverPacket(unavailiblePacket);

                }

                //update the corresponding changes in <items> table in sender's record used for delivery
                Packet item2 = (Packet)recipientRoster.items[user + "@" + JabberServer.server_name];
                if (item2 != null)
                {
                    item2.setAttribute("subscription", recipientsSubscriberItem.subscription);
                    item2.setAttribute("ask", recipientsSubscriberItem.ask);
                    Packet iq = new Packet("iq");
                    iq.Type = "set";
                    Packet query = new Packet("query");
                    query.setAttribute("xmlns", "jabber:iq:roster");
                    query.setParent(iq);
                    item2.setParent(query);
                    iq.To = recipientID.User + "@" + recipientID.Domain;
                    //Forward the subscription packet to recipient
                    MessageHandler.deliverPacketToAll(user, iq);//may need some correction!
                }

            }

            MessageHandler.deliverPacket(presence);


        }//UpdatePresense
		public void process(Session session) {
			//Assembly assem = Assembly.LoadFrom(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + @"\SaxExpat.dll");
			//IXmlReader reader = SaxReaderFactory.CreateReader(assem, null);
			//reader.ContentHandler = this;
			this.session = session;
			//reader.Parse(new ReaderInputSource(session.getReader()));

			XmlReader reader = XmlReader.Create(session.Reader);


            JabberServer.output.WriteLine("JIH:server version");

			reader.MoveToContent();


			try {
				do {
					switch (reader.Depth) {
						case 0:
							switch (reader.NodeType) {
								case XmlNodeType.Element:
									if (reader.Name == "stream:stream") {
										Dictionary<String, String> atts = getAttributes(reader);
										Packet openPacket = new Packet(null, reader.Name, reader.NamespaceURI, atts);
										openPacket.Session = (session);
										String from = atts["from"];
										session.JID = (new JabberID(from));
										packetQ.enqueue(openPacket);

									} else {
										throw new XmlException("Root node must be <stream:stream>");
									}
									break;
								case XmlNodeType.EndElement:
									Packet closePacket = new Packet("/stream:stream");
									closePacket.Session = (session);
									packetQ.enqueue(closePacket);
									break;
							}
							break;
						case 1:
							switch (reader.NodeType) {
								case XmlNodeType.Element:
									Dictionary<String, String> atts = getAttributes(reader);
									packet = new Packet(null, reader.Name, reader.NamespaceURI, atts);
									packet.Session = (session);
									if (reader.IsEmptyElement)
										goto case XmlNodeType.EndElement;
									break;
								case XmlNodeType.EndElement:
									packetQ.enqueue(packet);
									break;
							}
							break;
						default:
							switch (reader.NodeType) {
								case XmlNodeType.Element:
									Dictionary<String, String> atts = getAttributes(reader);
									Packet child = new Packet(packet, reader.Name, reader.NamespaceURI, atts);
									packet = child;
									if (reader.IsEmptyElement)
										goto case XmlNodeType.EndElement;
									break;
									
								case XmlNodeType.EndElement:
									packet = packet.Parent;
									break;
								case XmlNodeType.Text:
									packet.Children.Add(reader.Value);
									break;

							}
							break;
					}
				} while (reader.Read());

			} catch (Exception ex) {
                //JabberServer.output.WriteLine(ex.ToString());
				// Bilokakov problem so xml stream-ot
				// io-exception, invalid xml, zatvoren socket i sl.
				// treba da se napravi clean-up : zatvori stream </stream:stream>, zatvori socket, trgni Session object i sl.
				
				// Ne sekogas znaci greska : posle </stream:stream> se zatvara socket-ot i ne treba da se pravi nisto
 


                UserIndex userIndex = JabberServer.getUserIndex();
                if (!userIndex.containsSession(session))
                {
                    return;
                }
                //clean-up code (copied from CloseStreamHandler)
                try
                {
                    //      Log.trace("Closing session");
                    //Session session = packet.Session;

                    //session.Writer.Write("</stream:stream> ");
                    //session.Writer.Flush();

                    //notify other subscribers that user is unavailble
                    //by Marko
                    //begin
                    JabberID userid = session.getJID();

                    Packet unavailiblePacket = new Packet("presence");
                    unavailiblePacket.setFrom(userid.ToString());
                    unavailiblePacket.setAttribute("type", "unavailable");
                    userIndex.getUser(userid.User).getRoster().updateSubscribers(unavailiblePacket);
                    //it is not tested, but it should work
                    //end



						  //send groupchat presence unavailable & remove from groups
						  String jid = userid.ToString();

						  Packet presence = new Packet("presence");
						  presence.Type = "unavailable";
						  foreach (KeyValuePair<String, GroupChatManager.Group> kvp in GroupChatManager.Manager.groups) {

							  GroupChatManager.Group group = kvp.Value;
							  try {

								  String nick = group.jid2nick[jid]; // test whether the user is in the group
								  presence.From = group.JabberID + "/" + nick;
								  GroupChatManager.Manager.removeUser(group, jid);   // first remove then deliver so that the packet does not come back
								  GroupChatManager.Manager.deliverToGroup(group, presence);

							  } catch (Exception e) {
							  }
						  }
						  // end groupchar clean-up	

                    //session.Socket.Close();
                    userIndex.removeSession(session);
                    //      Log.trace("Closed session");
                }
                catch (Exception e)
                {
                    //      Log.error("CloseStreamHandler: ",ex);
                    userIndex.removeSession(packet.Session);
                    //      Log.trace("Exception closed session");
                }



			}

			
		}
        public void notify(Packet packet) {
            try
            {
                //      Log.trace("Closing session");
                Session session = packet.Session;

                session.Writer.Write("</stream:stream> ");
                session.Writer.Flush();

                //notify other subscribers that user is unavailble
                //by Marko
                //begin
                JabberID userid = session.getJID();

                Packet unavailiblePacket = new Packet("presence");
                unavailiblePacket.setFrom(userid.ToString());
                unavailiblePacket.setAttribute("type", "unavailable");
                userIndex.getUser(userid.User).getRoster().updateSubscribers(unavailiblePacket);
                //it is not tested, but it should work
                //end

                //send groupchat presence unavailable & remove from groups
                String jid = userid.ToString();

                Packet presence = new Packet("presence");
                presence.Type = "unavailable";
                foreach (KeyValuePair<String, GroupChatManager.Group> kvp in GroupChatManager.Manager.groups)
                {

                    GroupChatManager.Group group = kvp.Value;
                    try
                    {

                        String nick = group.jid2nick[jid]; // test whether the user is in the group
                        presence.From = group.JabberID + "/" + nick;
                        GroupChatManager.Manager.removeUser(group, jid);   // first remove then deliver so that the packet does not come back
                        GroupChatManager.Manager.deliverToGroup(group, presence);

                    }
                    catch (Exception ex)
                    {
                    }
                }
                // end groupchar clean-up	





                //session.Socket.Close();
                userIndex.removeSession(session);
                //      Log.trace("Closed session");
            }
            catch (Exception ex)
            {
                JabberServer.output.WriteLine(ex.ToString());
        //      Log.error("CloseStreamHandler: ",ex);
//              packet.Session.Socket.Close();
//              userIndex.removeSession(packet.Session);
        //      Log.trace("Exception closed session");
            }
            finally
            {
                packet.Session.Socket.Close();
            }

        }
		//end added by marko

		public void sendRosterSet(String jid, String name, string group) {			//hashtable type may be changed
			Packet packet = new Packet("iq");
			packet.Type = "set";
			packet.ID = "roster_set";
			Packet query = new Packet("query");
			query.setAttribute("xmlns", "jabber:iq:roster");
			query.setParent(packet);
			Packet item = new Packet("item");
			item.setAttribute("jid", jid);
			if(name != null) {
				item.setAttribute("name", name);
			}
			item.setParent(query);
			//code to form the packets
			if(group != null) {
				new Packet("group", group).setParent(item);
			}
			session.Writer.Write(packet.ToString());
			session.Writer.Flush();
		}
		public void sendRosterSet(String jid, String name, Hashtable groups)//hashtable type may be changed
		{
			Packet packet = new Packet("iq");
			packet.Type = "set";
			packet.ID = "roster_set";
			Packet query = new Packet("query");
			query.setAttribute("xmlns", "jabber:iq:roster");
			query.setParent(packet);
			Packet item = new Packet("item");
			item.setAttribute("jid", jid);
			item.setAttribute("name", name);
			item.setParent(query);
			//code to form the packets
			foreach (object key in groups.Keys) {
				new Packet("group", groups[key].ToString()).setParent(item);
			}
			session.Writer.Write(packet.ToString());
			session.Writer.Flush();
		}
		public void sendRosterRemove(String jid) {
			Packet packet = new Packet("iq");
			packet.Type = "set";
			packet.setID("roster_remove");
			Packet query = new Packet("query");
			query.setAttribute("xmlns", "jabber:iq:roster");
			query.Parent = packet;
			Packet item = new Packet("item");
			item.setAttribute("jid", jid);
			item.setAttribute("subscription", "remove");
			item.Parent = query;
			session.Writer.Write(packet.ToString());
			session.Writer.Flush();
		}
		//Крај додадено

		//added by marko
		//roster/presence management
		public void sendRosterGet() {
			Packet packet = new Packet("iq");
			packet.Type = "get";
			packet.ID = "roster_get_id";
			Packet query = new Packet("query");
			query.setAttribute("xmlns", "jabber:iq:roster");
			query.setParent(packet);
			session.Writer.Write(packet.ToString());
			session.Writer.Flush();
		}