aboutsummaryrefslogblamecommitdiffstats
path: root/src/lib/efreet/efreet_menu.c
blob: 06c2c418fb844dc5b9b0fd93890ba4e32b1f2c11 (plain) (tree)
1
2
3
4
5
6
7
8
9



                    
                  

                       

                                                                          



                                                                   

                           
                       
                   
 

                                                 

                       

                                                                

  

                                                         



                           

                                                                    





                                                                  
                                                                 
 


                                                        
                                                    
                                                                             


                                                            
                                                                           
 

                                                                    
 
                                                                     
                                                          
 

                                                                                  
 
                                                           
                                                        
 

                                                            




                                                                                                      







                                                                                 

                                                       

                          

                                                                           


                                                            






                               

                                                                   





                               

                                                             

                                                           


                                                                  

                                                                              
 
                                                         



                                                                          

                                                     





                                                                 







                                 

                                                             

                                                     


                                                               
                                                                    

                                                          




                                                                                                      

  

                                                       


                                                               
                                                          


                                                                         




                                                   
                           
                           
                           

  
                                                                                  
                                                                                                   
                                          
                                                                                         
 



                                                
 
                                                                                     
                                                                     






                                                                                                 
                   
                                                                                
      



                                                                                              
                                                                   



                                                                              
                                                           

                                                                      
                                                                                
                                                                      
                                                                       
                                                                           




                                                                              












                                                                                              
                                                           
 
                                                                                    








                                                                                   
                                                                                            

                                                          
                                                               







                                                                
                                                                

































                                                                                                    


                                                                                             







                                                                                             
                                                                                   

                                                                                    
                                                                                         















                                                                                                       
                                                                                                 
 

                                                                                   
                                                                         
                                                        
 






                      
                        



























                                                                            
                        












                                                              
                        








                                                                 
                        








                                                                          

                                                   

                                 
                                                                              
                 
     
 


                                                 

                                                    
 



                                                                  

                                                                
     
                                                         
                                  
                 
     
 

                                                                            
                                                            
 
                                     
     
                                             


                                        
                                       
     
                                             


                                          
                                     
     
                                           


                                        
                                       
     
                                             


                                          


             
        




                                 
 
                                                                    



                                             
                                                                        
                                                                     
                                    
     
                                                         
                  







                       
                                                                                   
                                                             



                           
           
                                                                                   
                                                             




              


                          
                                 





                                         
                                                                    
 

                                
                                                     
                              

 
                  
                                 

                      
 

                                               

                                        
                                            


                


                                      
                                 
                            
                                                            

 
                
                               
                                                                                    
 


                                                                  

 
                  

                     





























                                                                      
 
 
                
                               
                                                                                                                    
 


                                                                  

 
                  




                                          
 

                                               





                                                    
                                                                  



                            
                                               
                                              




                            

                                                                         







                                



                                                
                   





                                            
                   


                                          
                   


                                                      
                   


                                              

      

                                                



                                        
        
                                                     



            


                                            
                          



                                                                                  

                                            


               
        


                                                                               
                   
 


                                               
                                                         
                      


                                            


                                                                         
                                

                             
                                                                       
                                                               

        

                                                                                     
     


             
        
                                                                      


                       

                                               
 
                                                    
                                                                                            


                                     
                                                               





                                
         

                                                       

                 


                                       

                                                     






                                            
                   

                                 
                                 

                                                  
                                                  

                                                           
                                          
                                                              
                                                       


                                                             
                                                         
         



     
            
                                                    
                                                                        

                             
                                                      



                                            
                               





                                 





                                                                    



                    
                               
                           
                                           




                                                         
 

                                    



                                        
                                                                    
 
                                                              

                                                               
                                                                 

                                            

                                                             
 
                                                                 
 

                                                                    





                   

                                               

                                                               
  








                                                                         
                 

                                                             
                                                      
     
                                                                






                                     
                                                                                                              







                     

                                           
                                               

                                                    






                                                                          
                                                
                            
                                                                  







                                                                            
                                                             
                                                                                        
                                                      





                                                 
                                                                           





             

                                
                                               
                                



                                                                         
                     








                                                               
                                                   
                                                                                   
                                        
     
                                   



                                        
                         
 
                                                                    





             

                                



                                               
                                                                                              
 

                              






                                                                                    
                             
     




                                                                                        
 
                                                
                                                      
 

                                                         
 
                                  
     
                                                                  





             

                                





                                                                               
                     







                                                               
                                                                                         
     
                                   


                 
                                                                             





             

                                



                                               
                                                                                                    
 
                    




                                                   
                                                                                  
                                                                                   
                             
     
                                                                                             
                                                                                                          
                                  
     





             

                                  






                                                                      
                              
     
                                                                                                                      

                 

                                        



                                            
                                                            





             

                                











                                                                           
                                                                                                  





             

                                


















                                                                                  

                                


















                                                                                      

                                


















                                                                         

                                


















                                                                             

                                       
                                               
                                                         



                                                                         
                                                 




                                                            

                                





                                                                         
                                                 




                                                            

                                 







                                                                       
                                                                                     





             

                                 







                                                                       
 
                                                                                       





             

                                 














                                                                  

                                 







                                                                  
                                                      




                                                       

                                 







                                                                 
                                                      




                                                      

                                 







                                                                  
                                                      




                                                       

                                





                                                                            
                 
                            


















                                                                          
                               
                            
 
                               
         
                                                                                                 












                                                                            
                                       
                                                                          
         
                                                  
             
                                                                                   





                          

                                                                 




                                                                     
                                                             


                                                                           
                                              


                                
                                                            

                                                                           
             
                                                  










                                              
                               





               


                                                  





                                                                                  





                                              
                                         
                                                          
     
                 
     
 
                                                                
 
                                     
 
                   
     
                                                        
                                         


                 
                                                




                                  











                                                 

                                





                                                                           
                     





                                                   
                                 
     
                                   



                                                   
                               





               


                                              


                                                                           
   


                                                                                      

                                



                                                             

                                                                   
 

                                   
 
                                   


                
                                                        


                                         
                                                        
         
                                   
                     
         
     
                           





             

                                





                                                                                    
                    

                                   
                   
                                                
      

                                  
 

                                                                  
     

                                                          
     
        
     
                   
 














                                                                  
                        
 


                                                 


                                

                                                       
 
                                                            
                                                                    
 
                            
     

                                               
     




                                                                                 





             

                                











                                                                            




                                                






             


                                                       








                                                                             
                     


                                          

                      





                                                        
                                          
     
                                   


                    
                                                       

                         
                                                                                     


                                          
                                               
                        
                                                                                       

                                                      
                                                                                     
                   



                                                                          
                                                   
                            
                                                                                           
                                                                   




                                                            
                                                                                                                    



                                                                         




                                                   


                                                

                                                    
                                                                                  
 
                                 
           
     


                                       



                                           
                              
 
                                                  
                                              
                                            

                                          
 
                                                                                         
                                                             



                                                               
                                           

                                
 

                                                                                                
 


                         
                                             
             
                                                                            






                                                                                             

             
                                        
 
                                                    
                                                         
 



                                                                
             

                                             
             
 

                                                                      
 

                       
                                                                  


                                                                                                           
                                                                                                             
 
                    
                                         
         
                               
     
 
                               




                           

                                



                                               
                                                                                             
 
                 





                                               
                                                                                     
                                            
                                                          



                                                                             
                











                                                 

                                






                                                                      
                 




                                         
                                              


                                                                 
                                                              






                                   
                                                              

                                                               










                                

                                









                                                                     
                             
     
                                                        

                                                      




                                                                      
                   
                                                   
                                                                                  


                                                
                                                              
                                    
     


                                  
                                                     

                                
                                                          





             

                                









                                                                     

                                                                            


                 
                                                                     






                                

                                






                                                                        
                 







                                           
                                              


                                                                          
                                                                






                                      
                                                              

                                                                 








                     

                                







                                                                                
                 






















                                                          
                                              


                                                                          
                                                                






                                      
                                                                 

                                                                     
















                                                                                          
                                                                       

                                                          




                                               
                                                   















                                                          

                                                                                       












                                                                                          
                                                                       

                                                          




                                               
                                                   
 

                                                                                       













                                                                                           
                                                                                  
        
                                                                  













                                                                                       
                                                                        

                                                         




                                                                              
                                                                       

                                                                               




                                            
                                              
 

                                                                                       





             


                                   



                                                                          
                                                                        




                                                                     
 

                                                
                          








                                                       
                                                                 





             

                                                      






                                                                        
                 
 
                                              


                                                              
                                                                






                               

                                                                            
















                                                                         
                             











                                             
                                        



































                                                                         
                                        







                                                   
                             




                 
                                                                            
                                                                    












                                       
                                       






                                                     
 

                                                       
                                                          




















                                                                          
                                            





                                                 
                       
                                                      













                                                                  
                          


                 
         

                                    

                     

                       

                                      

                            

                                       
                          
                                                            


                


















                                             

            


                                       



                                                                        
                                                                              












                                                                                
                                                          





             

                                                                 






                                                                                  

                 











                                                                         
                                                               














                                                                        

                 











                                                         
                                                               










                                                   

                                                                             
                           
                                                                           

                                                                              
                                                               




                                                                                          


                            




                                                               
                                                                    


                                   
                                                   
     






                                                                      
                               
 
                                                           
                                                                                                             






                                                                                     
                                                                                           



                                                                                        
                                    



                                                                             

                                                
             
                                       
                                                               

                                                                                              





                                                                                
                                                
     
                                
 
                                                                 
         

                                                                                          
         


                                                                                            




            




                                                                   



                                                                               
                                                      
   

                                                                      

                                                                               

                            
                 
 
                                  
     
                                                      


                                                        
                                                              
                                                              


                              
                        



            

                                             







                                                                              
 










                                                      

                                            






                                                                                 
                 





                                                  
                                               
         
                                                                  
                                                                      





                         
                                              
                                      



                    
                                                










                                                      

                                            






                                                                                  
                 

            
                       
     
                                                                              

                     
                                               
         
                                                                   
                                                                       





                         
                                              
         
                                      




                    
                                                










                                                       

                                            






                                                                                  
                 






                                      
                                                                              

                     
                                               
         
                                                                  
                                                                      





                         
                                              
         
                                      




                    
                                                










                                                      

                                   































                                                                              

                                                                                 




                                               
                                                                        
                             




                                                     

                                                                                          




                                           
                                                               
                          




                                             
                                                                     
                            





                                               
                                                                              

                                        
 
                                                                       
                                                                         
                                                                   
                                                                                                
                                                             




                                                        
                                                                              





            
                                    







                                                         
                 



                                                     
                                                        




                                                 
 
                                               







                                                                             
                                                                        





                                                                           

                                 


                                                                          


                                             
                    






                                               
                                                            
                                          
                                                                    

                                                         
                                                                                  






                                              
                                                              

                                                     
                                                                            






                                                  
      
                                                         



            


                                               






                                                                                                         

                           



                                      


                           





                            
                                                                       
                                                                                                 
                                                         
         


                        






                                          
                                                                   
                                                                                             
                                                     
     


                    
                    

 
















                                                                              
                                           







                                             

                               


















                                                                          

            
                                             


                                       


                                                  

                     

                            
              

 

            

                                      
                                                              
                                  



                                                                      
                                 
                               
                              






                                                                
                               






                                                                
                              






                                                                      
                                    






                                                            
                           






                                                              
                             






                                                              
                            






                                                                      
                                    





                                                                   
 
                                 

 
                   










                                                                        
                                 
         
                                                                                                





                                                                           
                                                
 
                                      




                                                                             
                                                         
                                                       
                                                      





                                                            

                            
 
                                          
                                     
 
                                                     
                                                                                            
 







                                                                                                      


                                
 
                                 
                      
 
                                   
     

                          
                                              
               
                                                             
            



                                           
 
                                        

                        
                                                                             


            


                                      

                                                          
                                                     
 




                                                                             
                                                                      
                                                             
                                                                                         
                                                

                                                          
                         
             


                                                     
                                                          
                                                                                     

         
                           





             
                                    






                                                                  
                 


                                 
                                   
                                                                              
 
                                                                    




                                                                                  
                                                                 














                                                                            


                                                        
                                               
                                                                         


                            
                                                                           
                                                 

                            


                                

              
                                 
                      
 
                                   
     

                          
                                              
                          
                                                                        
            



                                           
 
                                        
                                                                    


            
                                      

                                                            
                                                     




                                                                           
 
                                             
                                                

         
                           





             

                                    









                                                                           
                                                              










                                                                 

                              



                                                      
                                                                                     
 
                  
                                                                                                          
     
                                                       






                                                                              
                                                  





                                                                        
                                 






                                                       

                             



























                                                                                                     

                                                              

                            
                                                                      
                                                
                                             
     
                          



                            

                                                                 
                                                                                           






                                
                                         








                                                                 
                                                          




                                                                                             




                                                
                                                                             






                                    
                                                            


                                                           
                                                                             




                                                    











                                                   


                                                                                 
                                    
































                                                                                     
                                                            
                                                                                                     




                                                                                 
                                                                          
                                                

                                               

                                                                                                                    
                 
                                
                                            

                                                           
                                                                                     
                     
                                                                                        
                     

                                         

                                                                                                           





                                                    
                                                                               
                                                    


                        

                                         

                                          





                                                                 





                                                                                                               
                         
                                                    

                     
                    
                                                                                 
             
                                                                             

                                           



                                                                                   
                                                              
                                                                                                     


                                                       

                                                                                  
         






                                                                     
                                                                     
             


                                                                                       
                                                                                                            
                                                                   


                                                               
                                                                                 

                 
                                                                            




                                                                       
                                                                   
             
                                                                                                      




                                                                                   
                                                                     
                                                                                                         
                                                           


                                                             
                                                                                        
                                                    

                                                             

                                                                                                                                            
                     
                                    
                                                

                                                               
                                                                                         
                         
                                                                                                      
                         

                                             

                                                                                                               
                                                            







                                                            
                                                                                   
                                                        


                            

                                             

                                                        





                                                                                 






                                                                                               
                             
                                                        

                         
                        
                                                                                     


                                               
                                                                         


                                                                     
                             
 





                                                                    





                                                          
                                                                     






                                                                                     
                                                       
                                                     
                                                    





                                                                                 
                                                  
                                               
                                              

 
                   


                                                                    
                                          

                                        
 
      




                                               
                 


                                  
                                                   





                                                                   






















































































































                                                                            
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <Ecore.h>
#include <Ecore_File.h>

/* TODO: Don't scan app dirs if they are cached, read values from cache */

/* define macros and variable for using the eina logging system  */
#define EFREET_MODULE_LOG_DOM _efreet_menu_log_dom
static int _efreet_menu_log_dom = -1;

#include "Efreet.h"
#include "efreet_private.h"
#include "efreet_xml.h"
#include <unistd.h>

typedef struct Efreet_Menu_Move Efreet_Menu_Move;

struct Efreet_Menu_Move
{
    const char *old_name;     /**< The menu path to move from */
    const char *new_name;     /**< The menu path to move too */
};

typedef struct Efreet_Menu_Internal Efreet_Menu_Internal;

struct Efreet_Menu_Internal
{
    struct
    {
        const char *path;         /**< The base file path */
        const char *name;         /**< The filename for this menu */
    } file;                 /**< The menu file information */

    struct
    {
        const char *internal;     /**< The menu name */
        const char *name;         /**< Name to use in the menus */
    } name;                       /**< The names for this menu */

    Eina_Hash *efreet_merged_menus; /**< Merged menus */
    Eina_Hash *efreet_merged_dirs; /**< Merged dirs */

    Efreet_Desktop *directory; /**< The directory */
    Eina_List *directories;  /**< All the directories set in the menu file */

    Efreet_Menu_Move *current_move; /**< The current move */

    Eina_List *app_dirs;           /**< .desktop application directories */

    Eina_List *app_pool;           /**< application pool */
    Eina_List *applications;       /**< applications in this menu */

    Eina_List *directory_dirs;    /**< .directory file directories */
    Eina_Hash *directory_cache;    /**< .directory dirs */

    Eina_List *moves;              /**< List of moves to be handled by the menu */
    Eina_List *filters;            /**< Include and Exclude filters */

    Efreet_Menu_Internal *parent;   /**< Our parent menu */
    Eina_List *sub_menus;          /**< Our sub menus */

    Eina_List *layout;             /**< This menus layout */
    Eina_List *default_layout;     /**< Default layout */
    signed char show_empty;    /**< Whether to show empty menus */
    signed char in_line;       /**< Whether this meny can be inlined */
    signed char inline_limit;  /**< Number of elements which triggers inline */
    signed char inline_header; /**< Whether we should use the header name when this menu is inlined */
    signed char inline_alias;  /**< Whether we should use the menu name when inlining */

    unsigned char seen_allocated:1;     /**< have we set the only_unallocated */
    unsigned char only_unallocated:1;   /**< Show only unallocated .desktops */

    unsigned char seen_deleted:1;       /**< Have we seen the deleted item yet */
    unsigned char deleted:1;            /**< The menu is deleted */
};

typedef struct Efreet_Menu_App_Dir Efreet_Menu_App_Dir;

struct Efreet_Menu_App_Dir
{
    const char *path;           /**< directory path */
    const char *prefix;         /**< If it's legacy it can have a prefix */
    unsigned int legacy:1;      /**< is this a legacy dir */
};

enum Efreet_Menu_Filter_Op_Type
{
    EFREET_MENU_FILTER_OP_OR,
    EFREET_MENU_FILTER_OP_AND,
    EFREET_MENU_FILTER_OP_NOT
};

typedef enum Efreet_Menu_Filter_Op_Type Efreet_Menu_Filter_Op_Type;

enum Efreet_Menu_Filter_Type
{
    EFREET_MENU_FILTER_INCLUDE,
    EFREET_MENU_FILTER_EXCLUDE
};

typedef enum Efreet_Menu_Filter_Type Efreet_Menu_Filter_Type;

typedef struct Efreet_Menu_Filter_Op Efreet_Menu_Filter_Op;

struct Efreet_Menu_Filter_Op
{
    Efreet_Menu_Filter_Op_Type type; /**< The type of operation */
    Eina_List *categories;          /**< The categories this op applies too */
    Eina_List *filenames;           /**< The filenames this op applies too */

    Eina_List *filters;             /**< Child filters */

    unsigned char all:1;             /**< Applies to all .desktop files */
};

typedef struct Efreet_Menu_Filter Efreet_Menu_Filter;

struct Efreet_Menu_Filter
{
    Efreet_Menu_Filter_Type type;   /**< The type of filter */
    Efreet_Menu_Filter_Op *op;      /**< The filter operations */
};

enum Efreet_Menu_Layout_Type
{
    EFREET_MENU_LAYOUT_MENUNAME,
    EFREET_MENU_LAYOUT_FILENAME,
    EFREET_MENU_LAYOUT_SEPARATOR,
    EFREET_MENU_LAYOUT_MERGE
};

typedef enum Efreet_Menu_Layout_Type Efreet_Menu_Layout_Type;

typedef struct Efreet_Menu_Layout Efreet_Menu_Layout;

struct Efreet_Menu_Layout
{
    Efreet_Menu_Layout_Type  type;   /**< The type of layout */
    const char *name;                /**< The name of the element */

    /* The items below are for Menuname Layout elements */
    signed char show_empty;    /**< Whether to show empty menus */
    signed char in_line;       /**< Whether this meny can be inlined */
    signed char inline_limit;  /**< Number of elements which triggers inline */
    signed char inline_header; /**< Whether we should use the header name when this menu is inlined */
    signed char inline_alias;  /**< Whether we should use the menu name when inlining */
};

typedef struct Efreet_Menu_Desktop Efreet_Menu_Desktop;

struct Efreet_Menu_Desktop
{
    Efreet_Desktop *desktop;   /**< The desktop we refer too */
    const char *id;            /**< The desktop file id */
    unsigned char allocated:1; /**< If this desktop has been allocated */
};

typedef struct Efreet_Menu_Async Efreet_Menu_Async;

struct Efreet_Menu_Async
{
    Efreet_Menu_Cb    func;
    void             *data;
    Eina_Stringshare *path;
    Efreet_Menu      *menu;
};

static const char *efreet_menu_prefix = NULL; /**< The $XDG_MENU_PREFIX env var */
Eina_List *efreet_menu_kde_legacy_dirs = NULL; /**< The directories to use for KDELegacy entries */
static const char *efreet_tag_menu = NULL;
static const char *efreet_menu_file = NULL; /**< A menu file set explicityl as default */

static Eina_Hash *efreet_menu_handle_cbs = NULL;
static Eina_Hash *efreet_menu_filter_cbs = NULL;
static Eina_Hash *efreet_menu_move_cbs = NULL;
static Eina_Hash *efreet_menu_layout_cbs = NULL;

static Efreet_Menu_Internal *efreet_menu_by_name_find(Efreet_Menu_Internal *internal,
                                                    const char *name,
                                                    Efreet_Menu_Internal **parent);
static int efreet_menu_cb_compare_names(Efreet_Menu_Internal *internal, const char *name);
static int efreet_menu_cb_md_compare_ids(Efreet_Menu_Desktop *md, const char *name);

static int efreet_menu_cb_entry_compare_menu(Efreet_Menu *entry, Efreet_Menu_Internal *internal);
static int efreet_menu_cb_entry_compare_desktop(Efreet_Menu *entry, Efreet_Desktop *desktop);

#ifndef STRICT_SPEC
static int efreet_menu_cb_move_compare(Efreet_Menu_Move *move, const char *old);
#endif

static int efreet_menu_process(Efreet_Menu_Internal *internal, unsigned int only_unallocated);
static int efreet_menu_process_dirs(Efreet_Menu_Internal *internal);
static int efreet_menu_app_dirs_process(Efreet_Menu_Internal *internal);
static int efreet_menu_app_dir_scan(Efreet_Menu_Internal *internal,
                                        const char *path,
                                        const char *id,
                                        int legacy);
static int efreet_menu_directory_dirs_process(Efreet_Menu_Internal *internal);
static int efreet_menu_directory_dir_scan(const char *path,
                                            const char *relative_path,
                                            Eina_Hash *cache);
static Efreet_Desktop *efreet_menu_directory_get(Efreet_Menu_Internal *internal,
                                                    const char *path);
static void efreet_menu_process_filters(Efreet_Menu_Internal *internal,
                                            unsigned int only_unallocated);
static Eina_List *efreet_menu_process_app_pool(Eina_List *pool,
                                               Eina_List *applications,
                                               Eina_Hash *matches,
                                               Efreet_Menu_Filter *filter,
                                               unsigned int only_unallocated);
static int efreet_menu_filter_matches(Efreet_Menu_Filter_Op *op,
                                        Efreet_Menu_Desktop *md);
static int efreet_menu_filter_or_matches(Efreet_Menu_Filter_Op *op,
                                            Efreet_Menu_Desktop *md);
static int efreet_menu_filter_and_matches(Efreet_Menu_Filter_Op *op,
                                            Efreet_Menu_Desktop *md);
static int efreet_menu_filter_not_matches(Efreet_Menu_Filter_Op *op,
                                            Efreet_Menu_Desktop *md);

static Efreet_Menu *efreet_menu_layout_menu(Efreet_Menu_Internal *internal);
static Efreet_Menu *efreet_menu_layout_desktop(Efreet_Menu_Desktop *md);
static void efreet_menu_layout_entries_get(Efreet_Menu *entry, Efreet_Menu_Internal *internal,
                                            Efreet_Menu_Layout *layout);
static int efreet_menu_layout_is_empty(Efreet_Menu *entry);

static Efreet_Menu_Internal *efreet_menu_internal_new(Efreet_Menu_Internal *parent);
static void efreet_menu_internal_free(Efreet_Menu_Internal *internal);
static void efreet_menu_create_sub_menu_list(Efreet_Menu_Internal *internal);
static void efreet_menu_create_app_dirs_list(Efreet_Menu_Internal *internal);
static void efreet_menu_create_directory_dirs_list(Efreet_Menu_Internal *internal);
static void efreet_menu_create_directories_list(Efreet_Menu_Internal *internal);
static void efreet_menu_create_move_list(Efreet_Menu_Internal *internal);
static void efreet_menu_create_filter_list(Efreet_Menu_Internal *internal);
static void efreet_menu_create_layout_list(Efreet_Menu_Internal *internal);
static void efreet_menu_create_default_layout_list(Efreet_Menu_Internal *internal);
static const char *efreet_menu_path_get(Efreet_Menu_Internal *internal, const char *suffix);

static Efreet_Menu_App_Dir *efreet_menu_app_dir_new(void);
static void efreet_menu_app_dir_free(Efreet_Menu_App_Dir *dir);

static Efreet_Menu_Move *efreet_menu_move_new(void);
static void efreet_menu_move_free(Efreet_Menu_Move *move);

static Efreet_Menu_Filter *efreet_menu_filter_new(void);
static void efreet_menu_filter_free(Efreet_Menu_Filter *filter);

static Efreet_Menu_Layout *efreet_menu_layout_new(void);
static void efreet_menu_layout_free(Efreet_Menu_Layout *layout);

static Efreet_Menu_Filter_Op *efreet_menu_filter_op_new(void);
static void efreet_menu_filter_op_free(Efreet_Menu_Filter_Op *op);

static Efreet_Menu_Desktop *efreet_menu_desktop_new(void);
static void efreet_menu_desktop_free(Efreet_Menu_Desktop *md);

static Efreet_Menu *efreet_menu_entry_new(void);

static int efreet_menu_handle_menu(Efreet_Menu_Internal *internal, Efreet_Xml *xml);
static int efreet_menu_handle_name(Efreet_Menu_Internal *parent, Efreet_Xml *xml);

static int efreet_menu_handle_sub_menu(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_app_dir(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_default_app_dirs(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_directory_dir(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_default_directory_dirs(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_directory(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_only_unallocated(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_not_only_unallocated(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_deleted(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_not_deleted(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_include(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_exclude(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_filename(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml);
static int efreet_menu_handle_category(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml);
static int efreet_menu_handle_all(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml);
static int efreet_menu_handle_and(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml);
static int efreet_menu_handle_or(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml);
static int efreet_menu_handle_not(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml);
static int efreet_menu_handle_merge_file(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_merge_dir(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_default_merge_dirs(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_legacy_dir(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static Efreet_Menu_Internal *efreet_menu_handle_legacy_dir_helper(Efreet_Menu_Internal *root,
                                                Efreet_Menu_Internal *parent,
                                                const char *legacy_dir,
                                                const char *prefix);
static int efreet_menu_handle_kde_legacy_dirs(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_move(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_old(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_new(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_layout(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
static int efreet_menu_handle_default_layout(Efreet_Menu_Internal *parent, Efreet_Xml *xml);

static int efreet_menu_handle_filter(Efreet_Menu_Internal *parent, Efreet_Xml *xml,
                                                    Efreet_Menu_Filter_Type type);
static int efreet_menu_handle_filter_op(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml);
static int efreet_menu_handle_filter_child_op(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml,
                                                      Efreet_Menu_Filter_Op_Type type);

static int efreet_menu_handle_layout_menuname(Efreet_Menu_Internal *parent, Efreet_Xml *xml, int def);
static int efreet_menu_handle_layout_filename(Efreet_Menu_Internal *parent, Efreet_Xml *xml, int def);
static int efreet_menu_handle_layout_separator(Efreet_Menu_Internal *parent, Efreet_Xml *xml, int def);
static int efreet_menu_handle_layout_merge(Efreet_Menu_Internal *parent, Efreet_Xml *xml, int def);

static int efreet_menu_merge(Efreet_Menu_Internal *parent, Efreet_Xml *xml, const char *path);
static int efreet_menu_merge_dir(Efreet_Menu_Internal *parent, Efreet_Xml *xml, const char *path);

static int efreet_menu_cb_app_dirs_compare(Efreet_Menu_App_Dir *a, const char *b);

static void efreet_menu_resolve_moves(Efreet_Menu_Internal *internal);
static void efreet_menu_concatenate(Efreet_Menu_Internal *dest, Efreet_Menu_Internal *src);

static int efreet_menu_cb_menu_compare(Efreet_Menu_Internal *a, Efreet_Menu_Internal *b);
static int efreet_menu_cb_md_compare(const Efreet_Menu_Desktop *a, const Efreet_Menu_Desktop *b);

static void efreet_menu_path_set(Efreet_Menu_Internal *internal, const char *path);

static int efreet_menu_save_menu(Efreet_Menu *menu, FILE *f, int indent);
static int efreet_menu_save_indent(FILE *f, int indent);

int
efreet_menu_init(void)
{
    int i;

    struct
    {
        const char *key;
        int (*cb)(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
    } menu_cbs[] = {
        {"Menu", efreet_menu_handle_sub_menu},
        {"AppDir", efreet_menu_handle_app_dir},
        {"DefaultAppDirs", efreet_menu_handle_default_app_dirs},
        {"DirectoryDir", efreet_menu_handle_directory_dir},
        {"DefaultDirectoryDirs", efreet_menu_handle_default_directory_dirs},
        {"Name", efreet_menu_handle_name},
        {"Directory", efreet_menu_handle_directory},
        {"OnlyUnallocated", efreet_menu_handle_only_unallocated},
        {"NotOnlyUnallocated", efreet_menu_handle_not_only_unallocated},
        {"Deleted", efreet_menu_handle_deleted},
        {"NotDeleted", efreet_menu_handle_not_deleted},
        {"Include", efreet_menu_handle_include},
        {"Exclude", efreet_menu_handle_exclude},
        {"MergeFile", efreet_menu_handle_merge_file},
        {"MergeDir", efreet_menu_handle_merge_dir},
        {"DefaultMergeDirs", efreet_menu_handle_default_merge_dirs},
        {"LegacyDir", efreet_menu_handle_legacy_dir},
        {"KDELegacyDirs", efreet_menu_handle_kde_legacy_dirs},
        {"Move", efreet_menu_handle_move},
        {"Layout", efreet_menu_handle_layout},
        {"DefaultLayout", efreet_menu_handle_default_layout},
        {NULL, NULL}
    };

    struct
    {
        const char *key;
        int (*cb)(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml);
    } filter_cbs[] = {
        {"Filename", efreet_menu_handle_filename},
        {"Category", efreet_menu_handle_category},
        {"All", efreet_menu_handle_all},
        {"And", efreet_menu_handle_and},
        {"Or", efreet_menu_handle_or},
        {"Not", efreet_menu_handle_not},
        {NULL, NULL}
    };

    struct
    {
        const char *key;
        int (*cb)(Efreet_Menu_Internal *parent, Efreet_Xml *xml);
    } move_cbs[] = {
        {"Old", efreet_menu_handle_old},
        {"New", efreet_menu_handle_new},
        {NULL, NULL}
    };

    struct
    {
        const char *key;
        int (*cb)(Efreet_Menu_Internal *parent, Efreet_Xml *xml, int def);
    } layout_cbs[] = {
        {"Menuname", efreet_menu_handle_layout_menuname},
        {"Filename", efreet_menu_handle_layout_filename},
        {"Separator", efreet_menu_handle_layout_separator},
        {"Merge", efreet_menu_handle_layout_merge},
        {NULL, NULL}
    };

    _efreet_menu_log_dom = eina_log_domain_register
      ("efreet_menu", EFREET_DEFAULT_LOG_COLOR);
    if (_efreet_menu_log_dom < 0)
    {
        EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_menu");
        return 0;
    }

#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
   if (getuid() == geteuid())
#endif
     efreet_menu_prefix = getenv("XDG_MENU_PREFIX");
   if (!efreet_menu_prefix) efreet_menu_prefix = "";

    efreet_menu_handle_cbs = eina_hash_string_superfast_new(NULL);
    efreet_menu_filter_cbs = eina_hash_string_superfast_new(NULL);
    efreet_menu_move_cbs = eina_hash_string_superfast_new(NULL);
    efreet_menu_layout_cbs = eina_hash_string_superfast_new(NULL);
    if (!efreet_menu_handle_cbs || !efreet_menu_filter_cbs
            || !efreet_menu_move_cbs || !efreet_menu_layout_cbs)
    {
        eina_log_domain_unregister(_efreet_menu_log_dom);
        _efreet_menu_log_dom = -1;
        return 0;
    }

    /* set Menu into it's own so we can check the XML is valid before trying
     * to handle it */
    efreet_tag_menu = eina_stringshare_add(menu_cbs[0].key);

    for (i = 0; menu_cbs[i].key; i++)
    {
        eina_hash_set(efreet_menu_handle_cbs,
                        menu_cbs[i].key,
                        menu_cbs[i].cb);
    }
    for (i = 0; filter_cbs[i].key; i++)
    {
        eina_hash_set(efreet_menu_filter_cbs,
                        filter_cbs[i].key,
                        filter_cbs[i].cb);
    }
    for (i = 0; move_cbs[i].key; i++)
    {
        eina_hash_set(efreet_menu_move_cbs,
                        move_cbs[i].key,
                        move_cbs[i].cb);
    }
    for (i = 0; layout_cbs[i].key; i++)
    {
        eina_hash_set(efreet_menu_layout_cbs,
                        layout_cbs[i].key,
                        layout_cbs[i].cb);
    }
    return 1;
}

EAPI int
efreet_menu_kde_legacy_init(void)
{
    FILE *f;
    char buf[PATH_MAX];
    char *p, *s;

    IF_FREE_LIST(efreet_menu_kde_legacy_dirs, eina_stringshare_del);

    f = popen("kde-config --path apps", "r");
    if (!f) return 0;

    /* XXX if the return from kde-config is a line longer than PATH_MAX,
     * this won't be correct (increase buffer and get the rest...) */
    if (!fgets(buf, sizeof(buf), f))
    {
        ERR("Error initializing KDE legacy information");
        pclose(f);
        return 0;
    }
    s = buf;

    p = strchr(s, ':');
    while (p)
    {
        *p = '\0';
        efreet_menu_kde_legacy_dirs = eina_list_append(efreet_menu_kde_legacy_dirs,
                            (void *)eina_stringshare_add(s));
        s = p + 1;
        p = strchr(s, ':');
    }

    if (*s)
        efreet_menu_kde_legacy_dirs = eina_list_append(efreet_menu_kde_legacy_dirs,
                            (void *)eina_stringshare_add(s));

    pclose(f);
    return 1;
}

void
efreet_menu_shutdown(void)
{
    IF_RELEASE(efreet_menu_file);

    IF_FREE_HASH(efreet_menu_handle_cbs);
    IF_FREE_HASH(efreet_menu_filter_cbs);
    IF_FREE_HASH(efreet_menu_move_cbs);
    IF_FREE_HASH(efreet_menu_layout_cbs);

    IF_FREE_LIST(efreet_menu_kde_legacy_dirs, eina_stringshare_del);

    IF_RELEASE(efreet_tag_menu);

    eina_log_domain_unregister(_efreet_menu_log_dom);
    _efreet_menu_log_dom = -1;
}

EAPI Efreet_Menu *
efreet_menu_new(const char *name)
{
    Efreet_Menu *menu;

    EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);

    menu = efreet_menu_entry_new();
    menu->type = EFREET_MENU_ENTRY_MENU;
    menu->name = eina_stringshare_add(name);
    return menu;
}

EAPI void
efreet_menu_file_set(const char *file)
{
    IF_RELEASE(efreet_menu_file);
    efreet_menu_file = NULL;
    if (file) efreet_menu_file = eina_stringshare_add(file);
}

/* deprecated */
EFREET_DEPRECATED_API EAPI void
efreet_menu_async_get(Efreet_Menu_Cb func EINA_UNUSED, const void *data EINA_UNUSED)
{
    ERR("%s is deprecated and shouldn't be called", __FUNCTION__);

    return;
}

EAPI Efreet_Menu *
efreet_menu_get(void)
{
    char menu[PATH_MAX];
    const char *dir;
    Eina_List *config_dirs, *l;

#ifndef STRICT_SPEC
    /* prefer user set menu */
    if (efreet_menu_file)
    {
        if (ecore_file_exists(efreet_menu_file))
            return efreet_menu_parse(efreet_menu_file);
    }
#endif

    /* check the users config directory first */
    snprintf(menu, sizeof(menu), "%s/menus/%sapplications.menu",
                        efreet_config_home_get(), efreet_menu_prefix);
    if (ecore_file_exists(menu))
        return efreet_menu_parse(menu);

    /* fallback to the XDG_CONFIG_DIRS */
    config_dirs = efreet_config_dirs_get();
    EINA_LIST_FOREACH(config_dirs, l, dir)
    {
        snprintf(menu, sizeof(menu), "%s/menus/%sapplications.menu",
                                    dir, efreet_menu_prefix);
        if (ecore_file_exists(menu))
            return efreet_menu_parse(menu);
    }

    return NULL;
}

/* deprecated */
EFREET_DEPRECATED_API EAPI void
efreet_menu_async_parse(const char *path EINA_UNUSED, Efreet_Menu_Cb func EINA_UNUSED, const void *data EINA_UNUSED)
{
    ERR("%s is deprecated and shouldn't be called", __FUNCTION__);

    return;
}

EAPI Efreet_Menu *
efreet_menu_parse(const char *path)
{
    Efreet_Xml *xml;
    Efreet_Menu_Internal *internal = NULL;
    Efreet_Menu *entry = NULL;

    EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);

    xml = efreet_xml_new(path);
    if (!xml) return NULL;

    /* make sure we've got a <Menu> to start with */
    if (xml->tag != efreet_tag_menu)
    {
        WRN("Menu file didn't start with <Menu> tag: '%s'", path);
        efreet_xml_del(xml);
        return NULL;
    }

    /* split apart the filename and the path */
    internal = efreet_menu_internal_new(NULL);
    if (!internal)
    {
        efreet_xml_del(xml);
        return NULL;
    }
    internal->efreet_merged_menus = eina_hash_string_superfast_new(NULL);
    internal->efreet_merged_dirs = eina_hash_string_superfast_new(NULL);

    /* Set default values */
    internal->show_empty = 0;
    internal->in_line = 0;
    internal->inline_limit = 4;
    internal->inline_header = 1;
    internal->inline_alias = 0;

    efreet_menu_path_set(internal, path);
    if (!efreet_menu_handle_menu(internal, xml))
    {
        efreet_xml_del(xml);
        goto error;
    }
    efreet_xml_del(xml);

    efreet_menu_resolve_moves(internal);

    if (!efreet_menu_process_dirs(internal))
        goto error;

    /* handle all .desktops */
    if (!efreet_menu_process(internal, 0))
        goto error;

    /* handle menus with only unallocated .desktops */
    if (!efreet_menu_process(internal, 1))
        goto error;

    /* layout menu */
    entry = efreet_menu_layout_menu(internal);

error:
    IF_FREE_HASH(internal->efreet_merged_menus);
    IF_FREE_HASH(internal->efreet_merged_dirs);
    efreet_menu_internal_free(internal);
    return entry;
}

EAPI int
efreet_menu_save(Efreet_Menu *menu, const char *path)
{
    FILE *f;
    int ret;

    EINA_SAFETY_ON_NULL_RETURN_VAL(menu, 0);
    EINA_SAFETY_ON_NULL_RETURN_VAL(path, 0);

    f = fopen(path, "wb");
    if (!f) return 0;
    fprintf(f, "<?xml version=\"1.0\"?>\n");
    fprintf(f, "<!DOCTYPE Menu PUBLIC \"-//freedesktop//DTD Menu 1.0//EN\" "
                "\"http://standards.freedesktop.org/menu-spec/menu-1.0.dtd\">\n");
    ret = efreet_menu_save_menu(menu, f, 0);
    fclose(f);
    return ret;
}

EAPI int
efreet_menu_desktop_insert(Efreet_Menu *menu, Efreet_Desktop *desktop, int pos)
{
    Efreet_Menu *entry;
    const char *id;

    EINA_SAFETY_ON_NULL_RETURN_VAL(menu, 0);
    EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, 0);

    id = efreet_util_path_to_file_id(desktop->orig_path);
    if (!id) return 0;

    entry = efreet_menu_entry_new();
    entry->type = EFREET_MENU_ENTRY_DESKTOP;
    entry->id = eina_stringshare_add(id);
    entry->name = eina_stringshare_add(desktop->name);
    if (desktop->icon) entry->icon = eina_stringshare_add(desktop->icon);
    efreet_desktop_ref(desktop);
    entry->desktop = desktop;

    if (pos < 0 || (unsigned int)pos >= eina_list_count(menu->entries))
        menu->entries = eina_list_append(menu->entries, entry);
    else
    {
        menu->entries = eina_list_append_relative(menu->entries, entry,
                                                  eina_list_nth(menu->entries, pos));
    }
    return 1;
}

EAPI int
efreet_menu_desktop_remove(Efreet_Menu *menu, Efreet_Desktop *desktop)
{
    Efreet_Menu *entry;

    EINA_SAFETY_ON_NULL_RETURN_VAL(menu, 0);
    EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, 0);

    entry = eina_list_search_unsorted(menu->entries,
                                      EINA_COMPARE_CB(efreet_menu_cb_entry_compare_desktop),
                            desktop);
    if (entry)
    {
        menu->entries = eina_list_remove(menu->entries, entry);
        efreet_menu_free(entry);
        return 1;
    }
    return 0;
}

EAPI void
efreet_menu_dump(Efreet_Menu *menu, const char *indent)
{
    Eina_List *l;

    EINA_SAFETY_ON_NULL_RETURN(menu);
    EINA_SAFETY_ON_NULL_RETURN(indent);

    INF("%s%s: ", indent, menu->name);
    INF("%s", (menu->icon ? menu->icon : "No icon"));

    /* XXX dump the rest of the menu info */

    if (menu->entries)
    {
        Efreet_Menu *entry;
        char *new_indent;
        size_t len;

        len = strlen(indent) + 3;
        new_indent = alloca(len);
        snprintf(new_indent, len, "%s  ", indent);

        EINA_LIST_FOREACH(menu->entries, l, entry)
        {
            if (entry->type == EFREET_MENU_ENTRY_SEPARATOR)
                INF("%s|---", new_indent);
            else if (entry->type == EFREET_MENU_ENTRY_DESKTOP)
                INF("%s|-%s", new_indent, entry->name);
            else if (entry->type == EFREET_MENU_ENTRY_MENU)
                efreet_menu_dump(entry, new_indent);
            else if (entry->type == EFREET_MENU_ENTRY_HEADER)
                INF("%s|---%s", new_indent, entry->name);
        }
    }
}

/**
 * @internal
 * @return Returns a new Efreet_Menu_Internal struct
 * @brief Allocates and initializes a new Efreet_Menu_Internal structure
 */
static Efreet_Menu_Internal *
efreet_menu_internal_new(Efreet_Menu_Internal *parent)
{
    Efreet_Menu_Internal *internal;

    internal = NEW(Efreet_Menu_Internal, 1);
    if (!internal) return NULL;
    internal->show_empty = -1;
    internal->in_line = -1;
    internal->inline_limit = -1;
    internal->inline_header = -1;
    internal->inline_alias = -1;

    if (parent)
    {
        internal->efreet_merged_menus = parent->efreet_merged_menus;
        internal->efreet_merged_dirs = parent->efreet_merged_dirs;
    }

    return internal;
}

/**
 * @param menu The menu to free
 * @return Returns no value
 * @brief Frees up the given menu structure
 */
void
efreet_menu_internal_free(Efreet_Menu_Internal *internal)
{
    if (!internal) return;

    IF_RELEASE(internal->file.path);
    IF_RELEASE(internal->file.name);

    IF_RELEASE(internal->name.internal);
    internal->name.name = NULL;

    internal->applications = eina_list_free(internal->applications);

    IF_FREE_LIST(internal->directories, eina_stringshare_del);
    IF_FREE_LIST(internal->app_dirs, efreet_menu_app_dir_free);
    IF_FREE_LIST(internal->app_pool, efreet_menu_desktop_free);
    IF_FREE_LIST(internal->directory_dirs, eina_stringshare_del);
    IF_FREE_HASH(internal->directory_cache);

    IF_FREE_LIST(internal->moves, efreet_menu_move_free);
    IF_FREE_LIST(internal->filters, efreet_menu_filter_free);

    IF_FREE_LIST(internal->sub_menus, efreet_menu_internal_free);

    IF_FREE_LIST(internal->layout, efreet_menu_layout_free);
    IF_FREE_LIST(internal->default_layout, efreet_menu_layout_free);

    FREE(internal);
}

/**
 * @internal
 * @param menu The menu to populate
 * @param xml The xml dom tree to populate from
 * @return Returns 1 if this XML tree is valid, 0 otherwise
 * @brief Populates the given menu from the given xml structure
 *
 * We walk the Menu children backwards. The reason for this is so that we
 * can deal with all the things that make us select the 'last' element
 * (MergeFile, Directory, etc). We'll see the last one first and can deal
 * with it right away.
 */
static int
efreet_menu_handle_menu(Efreet_Menu_Internal *internal, Efreet_Xml *xml)
{
    Efreet_Xml *child;
    Eina_List *l;
    int (*cb)(Efreet_Menu_Internal *parent, Efreet_Xml *xml);

    EINA_LIST_REVERSE_FOREACH(xml->children, l, child)
    {
        cb = eina_hash_find(efreet_menu_handle_cbs, child->tag);
        if (cb)
        {
            if (!cb(internal, child))
                return 0;
        }
        else
        {
            WRN("Unknown XML tag '%s' in file '%s/%s'", child->tag, internal->file.path, internal->file.name);
            return 0;
        }
    }
    return 1;
}

/**
 * @internal
 * @param parent The parent Menu
 * @param xml The xml that defines the menu
 * @return Returns 1 on success or 0 on failure
 * @brief Handles the sub-menu nodes of the XML file
 */
static int
efreet_menu_handle_sub_menu(Efreet_Menu_Internal *parent, Efreet_Xml *xml)
{
    Efreet_Menu_Internal *internal, *match;

    efreet_menu_create_sub_menu_list(parent);

    internal = efreet_menu_internal_new(parent);
    if (!internal) return 0;
    internal->file.path = eina_stringshare_add(parent->file.path);
    if (!efreet_menu_handle_menu(internal, xml))
    {
        efreet_menu_internal_free(internal);
        return 0;
    }

    /* if this menu already exists we just take this one and stick it on the
     * start of the existing one */
    if ((match = eina_list_search_unsorted(parent->sub_menus,
                                           EINA_COMPARE_CB(efreet_menu_cb_menu_compare),
                                           internal)))
    {

        efreet_menu_concatenate(match, internal);
        efreet_menu_internal_free(internal);
    }
    else
        parent->sub_menus = eina_list_prepend(parent->sub_menus, internal);

    return 1;
}

/**
 * @internal
 * @param parent The parent menu
 * @param xml The xml tree
 * @return Returns 1 on success or 0 on failure
 * @brief Handles the AppDir tag
 */
static int
efreet_menu_handle_app_dir(Efreet_Menu_Internal *parent, Efreet_Xml *xml)
{
    const char *path;
    Efreet_Menu_App_Dir *app_dir;

    if (!parent || !xml) return 0;

    efreet_menu_create_app_dirs_list(parent);
    path = efreet_menu_path_get(parent, xml->text);
    if (!path) return 0;

    /* we've already got this guy in our list we can skip it */
    if (eina_list_search_unsorted(parent->app_dirs,
                                  EINA_COMPARE_CB(efreet_menu_cb_app_dirs_compare),
                                  path))
    {
        eina_stringshare_del(path);
        return 1;
    }

    app_dir = efreet_menu_app_dir_new();
    app_dir->path = path;

    parent->app_dirs = eina_list_prepend(parent->app_dirs, app_dir);

    return 1;
}

/**
 * @internal
 * @param parent The parent menu
 * @param xml UNUSED
 * @return Returns 1 on success or 0 on failure
 * @brief Handles the DefaultAppDirs
 */
static int
efreet_menu_handle_default_app_dirs(Efreet_Menu_Internal *parent, Efreet_Xml *xml EINA_UNUSED)
{
    Eina_List *prepend = NULL;
    Eina_List *dirs;
    char *dir;

    if (!parent) return 0;

    efreet_menu_create_app_dirs_list(parent);
    dirs = efreet_default_dirs_get(efreet_data_home_get(), efreet_data_dirs_get(),
                                                                    "applications");
    EINA_LIST_FREE(dirs, dir)
    {
        if (!eina_list_search_unsorted(parent->app_dirs,
                                       EINA_COMPARE_CB(efreet_menu_cb_app_dirs_compare),
                                       dir))
        {
            Efreet_Menu_App_Dir *app_dir;

            app_dir = efreet_menu_app_dir_new();
            app_dir->path = eina_stringshare_ref(dir);

            prepend = eina_list_append(prepend, app_dir);
        }

        eina_stringshare_del(dir);
    }
    parent->app_dirs = eina_list_merge(prepend, parent->app_dirs);

    return 1;
}

/**
 * @internal
 * @param parent The parent menu
 * @param xml The xml tree
 * @return Returns 1 on success or 0 on failure
 * @brief Handles the DirectoryDir tag
 */
static int
efreet_menu_handle_directory_dir(Efreet_Menu_Internal *parent, Efreet_Xml *xml)
{
    const char *path;

    if (!parent || !xml) return 0;

    efreet_menu_create_directory_dirs_list(parent);
    path = efreet_menu_path_get(parent, xml->text);
    if (!path) return 0;

    /* we've already got this guy in our list we can skip it */
    if (eina_list_search_unsorted(parent->directory_dirs, EINA_COMPARE_CB(strcmp), path))
    {
        eina_stringshare_del(path);
        return 1;
    }

    parent->directory_dirs = eina_list_prepend(parent->directory_dirs, path);

    return 1;
}

/**
 * @internal
 * @param parent The parent menu
 * @param xml UNUSED
 * @return Returns 1 on success or 0 on failure
 * @brief Handles the DefaultDirectoryDirs tag
 */
static int
efreet_menu_handle_default_directory_dirs(Efreet_Menu_Internal *parent, Efreet_Xml *xml EINA_UNUSED)
{
    Eina_List *dirs;
    char *dir;

    if (!parent) return 0;

    efreet_menu_create_directory_dirs_list(parent);
    dirs = efreet_default_dirs_get(efreet_data_home_get(), efreet_data_dirs_get(),
                                                            "desktop-directories");
    EINA_LIST_FREE(dirs, dir)
    {
        if (!eina_list_search_unsorted(parent->directory_dirs, EINA_COMPARE_CB(strcmp), dir))
            parent->directory_dirs = eina_list_prepend(parent->directory_dirs, eina_stringshare_ref(dir));
        eina_stringshare_del(dir);
    }

    return 1;
}

/**
 * @internal
 * @param parent The parent Menu
 * @param xml The xml to work with
 * @return Returns 1 on success or 0 on failure
 * @brief Sets the menu name from the given XML fragment.
 */
static int
efreet_menu_handle_name(Efreet_Menu_Internal *parent, Efreet_Xml *xml)
{
    /* not allowed to have two Name settings in a menu */
    if (parent->name.internal)
    {
        INF("efreet_menu_handle_name() setting second name into menu: '%s/%s'", parent->file.path, parent->file.name);
        return 0;
    }
    /* ignore the name if it is empty */
    if (!xml->text) return 1;

    /* ignore the name if it contains a / */
    if (strchr(xml->text, '/')) return 1;

    parent->name.internal = eina_stringshare_add(xml->text);

    return 1;
}

/**
 * @internal
 * @param parent The parent menu
 * @param xml The xml tree
 * @return Returns 1 on success or 0 on failure
 * @brief Handles the Directory tag
 *
 * This just adds the given directory path to a list which we'll walk once
 * we've traversed the entire menu into memory.
 */
static int
efreet_menu_handle_directory(Efreet_Menu_Internal *parent, Efreet_Xml *xml)
{
    if (!parent || !xml) return 0;

    efreet_menu_create_directories_list(parent);
    parent->directories = eina_list_prepend(parent->directories, eina_stringshare_add(xml->text));

    return 1;
}

/**
 * @internal
 * @param parent The parent menu
 * @param xml The xml tree
 * @return Returns 1 on success or 0 on failure
 * @brief Handles the OnlyUnallocated tag
 */
static int
efreet_menu_handle_only_unallocated(Efreet_Menu_Internal *parent, Efreet_Xml *xml)
{
    if (!parent || !xml) return 0;

    /* a later instance has been seen so we can ignore this one */
    if (parent->seen_allocated) return 1;

    parent->seen_allocated = 1;
    parent->only_unallocated = 1;

    return 1;
}

/**
 * @internal
 * @param parent The parent menu
 * @param xml The xml tree
 * @return Returns 1 on success or 0 on failure
 * @brief Handles the NotOnlyUnallocated tag
 */
static int
efreet_menu_handle_not_only_unallocated(Efreet_Menu_Internal *parent, Efreet_Xml *xml)
{
    if (!parent || !xml) return 0;

    /* a later instance has been seen so we can ignore this one */
    if (parent->seen_allocated) return 1;

    parent->seen_allocated = 1;
    parent->only_unallocated = 0;

    return 1;
}

/**
 * @internal
 * @param parent The parent menu
 * @param xml The xml tree
 * @return Returns 1 on success or 0 on failure
 * @brief Handles the Deleted tag
 */
static int
efreet_menu_handle_deleted(Efreet_Menu_Internal *parent, Efreet_Xml *xml)
{
    if (!parent || !xml) return 0;

    /* a later instance has been seen so we can ignore this one */
    if (parent->seen_deleted) return 1;

    parent->seen_deleted = 1;
    parent->deleted = 1;

    return 1;
}

/**
 * @internal
 * @param parent The parent menu
 * @param xml The xml tree
 * @return Returns 1 on success or 0 on failure
 * @brief Handles the NotDeleted tag
 */
static int
efreet_menu_handle_not_deleted(Efreet_Menu_Internal *parent, Efreet_Xml *xml)
{
    if (!parent || !xml) return 0;

    /* a later instance has been seen so we can ignore this one */
    if (parent->seen_deleted) return 1;

    parent->seen_deleted = 1;
    parent->deleted = 0;

    return 1;
}

/**
 * @internal
 * @param parent The parent menu
 * @param xml The XML tree to work with
 * @return Returns 1 on success or 0 on failure
 * @brief Handles parsing the Include tag and all subtags
 */
static int
efreet_menu_handle_include(Efreet_Menu_Internal *parent, Efreet_Xml *xml)
{
    return efreet_menu_handle_filter(parent, xml,
                                EFREET_MENU_FILTER_INCLUDE);
}

/**
 * @internal
 * @param parent The parent menu
 * @param xml The xml tree
 * @return Returns 1 on success or 0 on failure
 * @brief Handles the Exclude tag and all subtags
 */
static int
efreet_menu_handle_exclude(Efreet_Menu_Internal *parent, Efreet_Xml *xml)
{
    return efreet_menu_handle_filter(parent, xml,
                                EFREET_MENU_FILTER_EXCLUDE);
}

/**
 * @internal
 * @param op The filter operation
 * @param xml The xml tree
 * @return Returns 1 on success or 0 on failure
 * @brief Handles the Filename tag
 */
static int
efreet_menu_handle_filename(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml)
{
    if (!op || !xml) return 0;

    op->filenames = eina_list_append(op->filenames, eina_stringshare_add(xml->text));

    return 1;
}

/**
 * @internal
 * @param op The filter operation
 * @param xml The xml tree
 * @return Returns 1 on success or 0 on failure
 * @brief Handles the Category tag
 */
static int
efreet_menu_handle_category(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml)
{
    if (!op || !xml) return 0;


    op->categories = eina_list_append(op->categories, eina_stringshare_add(xml->text));

    return 1;
}

/**
 * @internal
 * @param op The filter operation
 * @param xml The xml tree
 * @return Returns 1 on success or 0 on failure
 * @brief Handles the All tag and all subtags
 */
static int
efreet_menu_handle_all(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml)
{
    if (!op || !xml) return 0;

    op->all = 1;

    return 1;
}

/**
 * @internal
 * @param op The filter operation
 * @param xml The xml tree
 * @return Returns 1 on success or 0 on failure
 * @brief Handles the And tag and all subtags
 */
static int
efreet_menu_handle_and(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml)
{
    if (!op || !xml) return 0;

    return efreet_menu_handle_filter_child_op(op, xml,
                            EFREET_MENU_FILTER_OP_AND);
}

/**
 * @internal
 * @param op The filter operation
 * @param xml The xml tree
 * @return Returns 1 on success or 0 on failure
 * @brief Handles the Or tag and all subtags
 */
static int
efreet_menu_handle_or(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml)
{
    if (!op || !xml) return 0;

    return efreet_menu_handle_filter_child_op(op, xml,
                            EFREET_MENU_FILTER_OP_OR);
}

/**
 * @internal
 * @param op The filter operation
 * @param xml The xml tree
 * @return Returns 1 on success or 0 on failure
 * @brief Handles the Not tag and all subtags
 */
static int
efreet_menu_handle_not(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml)
{
    if (!op || !xml) return 0;

    return efreet_menu_handle_filter_child_op(op, xml,
                            EFREET_MENU_FILTER_OP_NOT);
}

/**
 * @internal
 * @param parent The parent menu
 * @param xml The xml tree
 * @return Returns 1 on success or 0 on failure
 * @brief Handles the MergeFile tag
 */
static int
efreet_menu_handle_merge_file(Efreet_Menu_Internal *parent, Efreet_Xml *xml)
{
    Eina_List *l;
    const char *path = NULL;
    const char *attr = NULL;
    int is_path = 1;
    int ret = 1;

    if (!parent || !xml) return 0;

    /* check to see if this is a path or parent type */
    attr = efreet_xml_attribute_get(xml, "type");
    if (attr && !strcmp(attr, "parent"))
        is_path = 0;

    /* we're given a path */
    if (is_path)
        path = efreet_menu_path_get(parent, xml->text);

    /* need to find the next menu with the same name as ours in the config
     * dir after ours (if we're in a config dir) */
    else
    {
        Eina_List *search_dirs;
        const char *dir, *p;

        if (!parent->file.path)
        {
            INF("efreet_menu_handle_merge_file() missing menu path ... '%s'", parent->file.name);
            return 0;
        }

        search_dirs = efreet_config_dirs_get();

        /* we need to find the next menu with the same name in the directory
         * after the on the the menu was found in. to do that we first check
         * if it's in the config_home_directory() if so we need to search
         * all of the dirs. If it isn't in the config home directory then we
         * scan the search dirs and look for it. The search_dirs list will
         * be left at the next pointer so we can start looking for the menu
         * from that point */

        dir = efreet_config_home_get();
        if (strncmp(dir, parent->file.path, eina_stringshare_strlen(dir)))
        {
            EINA_LIST_FOREACH(search_dirs, l, dir)
            {
                if (!strncmp(dir, parent->file.path, eina_stringshare_strlen(dir)))
                    break;
            }
        }

        if (!dir)
        {
            INF("efreet_menu_handle_merge_file() failed to find "
                    "menu parent directory");
            return 0;
        }

        /* the parent file path may have more path then just the base
         * directory so we need to append that as well */
        p = parent->file.path + eina_stringshare_strlen(dir);

        /* whatever dirs are left in the search dir we need to look for the
         * menu with the same relative filename */
        EINA_LIST_FOREACH(search_dirs, l, dir)
        {
            char file[PATH_MAX];

            snprintf(file, sizeof(file), "%s/%s/%s", dir, p,
                                                        parent->file.name);
            if (ecore_file_exists(file))
            {
                path = eina_stringshare_add(file);
                break;
            }
        }
    }

    /* nothing to do if no file found */
    if (!path) return 1;

    if (!efreet_menu_merge(parent, xml, path))
        ret = 0;

    eina_stringshare_del(path);

    return ret;
}

/**
 * @internal
 * @param parent The parent menu to merge into
 * @param xml The XML to be merged
 * @param path The path to the .menu file to merge
 */
static int
efreet_menu_merge(Efreet_Menu_Internal *parent, Efreet_Xml *xml, const char *path)
{
    Efreet_Xml *merge_xml;
    Efreet_Menu_Internal *internal;

    if (!parent || !xml || !path) return 0;

    /* do nothing if the file doesn't exist */
    if (!ecore_file_exists(path)) return 1;

    /* don't merge the same path twice */
    if (eina_hash_find(parent->efreet_merged_menus, path))
    {
        return 1;
    }

    eina_hash_add(parent->efreet_merged_menus, path, (void *)1);

    merge_xml = efreet_xml_new(path);

    if (!merge_xml)
    {
        INF("efreet_menu_merge() failed to read in the "
                "merge file '%s'", path);
        return 0;
    }

    internal = efreet_menu_internal_new(parent);
    if (!internal)
    {
        efreet_xml_del(merge_xml);
        return 0;
    }
    efreet_menu_path_set(internal, path);
    efreet_menu_handle_menu(internal, merge_xml);
    efreet_menu_concatenate(parent, internal);
    efreet_menu_internal_free(internal);

    efreet_xml_del(merge_xml);

    return 1;
}

/**
 * @internal
 * @param parent The parent menu
 * @param xml The xml tree
 * @return Returns 1 on success or 0 on failure
 * @brief Handles the MergeDir tag
 */
static int
efreet_menu_handle_merge_dir(Efreet_Menu_Internal *parent, Efreet_Xml *xml)
{
    const char *path;
    int ret;

    if (!parent || !xml || !xml->text) return 0;

    path = efreet_menu_path_get(parent, xml->text);
    if (!path) return 1;
    if (!ecore_file_exists(path))
    {
        eina_stringshare_del(path);
        return 1;
    }

    ret = efreet_menu_merge_dir(parent, xml, path);
    eina_stringshare_del(path);

    return ret;
}

/**
 * @internal
 * @param parent the parent menu of the merge
 * @param xml The xml tree
 * @param path The path to the merge directory
 * @return Returns 1 on success or 0 on failure
 * @brief Find all of the .menu files in the given directory and merge them
 * into the @a parent menu.
 */
static int
efreet_menu_merge_dir(Efreet_Menu_Internal *parent, Efreet_Xml *xml, const char *path)
{
    Eina_Iterator *it;
    Eina_File_Direct_Info *info;

    if (!parent || !xml || !path) return 0;

    /* check to see if we've merged this directory already */
    if (eina_hash_find(parent->efreet_merged_dirs, path)) return 1;
    eina_hash_add(parent->efreet_merged_dirs, path, (void *)1);

    it = eina_file_direct_ls(path);
    if (!it) return 1;

    EINA_ITERATOR_FOREACH(it, info)
    {
        char *p;

        p = strrchr(info->path + info->name_start, '.');
        if (!p) continue;
        if (strcmp(p, ".menu")) continue;

        if (!efreet_menu_merge(parent, xml, info->path))
        {
            eina_iterator_free(it);
            return 0;
        }
    }
    eina_iterator_free(it);

    return 1;
}

/**
 * @internal
 * @param parent The parent menu
 * @param xml The xml tree
 * @return Returns 1 on success or 0 on failure
 * @brief Handles the DefaultMergeDirs tag
 */
static int
efreet_menu_handle_default_merge_dirs(Efreet_Menu_Internal *parent, Efreet_Xml *xml)
{
    Eina_List *dirs;
    char path[PATH_MAX], *p = NULL;
    const char *pp;
#ifndef STRICT_SPEC
    char parent_path[PATH_MAX + PATH_MAX + 128];
#endif

    if (!parent || !xml) return 0;

    if ((!strcmp(parent->file.name, "gnome-applications.menu")) ||
        (!strcmp(parent->file.name, "kde-applications.menu")))
    {
        p = alloca(sizeof("applications"));
        memcpy(p, "applications", sizeof("applications"));
    }
    else
    {
        size_t len;

        len = strlen(efreet_menu_prefix);
        if (!strncmp(parent->file.name, efreet_menu_prefix, len))
        {
            pp = parent->file.name;
            pp += len;
            if (!strcmp(pp, "applications.menu"))
            {
                p = alloca(sizeof("applications"));
                memcpy(p, "applications", sizeof("applications"));
            }
        }

        if (!p)
        {
            char *s;
            size_t len2;

            len2 = strlen(parent->file.name) + 1;
            p = alloca(len2);
            memcpy(p, parent->file.name, len2);
            s = strrchr(p, '.');
            if (s) *s = '\0';
        }
    }
    snprintf(path, sizeof(path), "menus/%s-merged", p);

    dirs = efreet_default_dirs_get(efreet_config_home_get(),
                                    efreet_config_dirs_get(), path);

    EINA_LIST_FREE(dirs, pp)
    {
        efreet_menu_merge_dir(parent, xml, pp);
        eina_stringshare_del(pp);
    }
#ifndef STRICT_SPEC
    /* Also check the path of the parent file */
    snprintf(parent_path, sizeof(parent_path), "%s/%s", parent->file.path, path);
    efreet_menu_merge_dir(parent, xml, parent_path);
#endif

    return 1;
}

/**
 * @internal
 * @param parent The parent menu
 * @param xml The xml tree
 * @return Returns 1 on success or 0 on failure
 * @brief Handles the LegacyDir tag
 */
static int
efreet_menu_handle_legacy_dir(Efreet_Menu_Internal *parent, Efreet_Xml *xml)
{
    Efreet_Menu_Internal *legacy;

    if (!parent || !xml) return 0;

    legacy = efreet_menu_handle_legacy_dir_helper(NULL, parent, xml->text,
                                efreet_xml_attribute_get(xml, "prefix"));
    if (legacy)
    {
        efreet_menu_concatenate(parent, legacy);
        efreet_menu_internal_free(legacy);
    }

    return 1;

}

/**
 * @internal
 * @param parent The parent menu
 * @param legacy_dir The legacy directory path
 * @param prefix The legacy directory prefix if one set
 * @return Returns the Efreet_Menu_Internal representing the legacy hierarchy
 * @brief Handles the process of merging @a legacy_dir into @a parent menu
 */
static Efreet_Menu_Internal *
efreet_menu_handle_legacy_dir_helper(Efreet_Menu_Internal *root,
                                        Efreet_Menu_Internal *parent,
                                        const char *legacy_dir,
                                        const char *prefix)
{
    const char *path;
    Efreet_Menu_Internal *legacy_internal;
    Efreet_Menu_Filter *filter;
    Efreet_Menu_App_Dir *app_dir;
    int count = 0;
    Eina_Iterator *it;

    if (!parent || !legacy_dir) return 0;

    path = efreet_menu_path_get(parent, legacy_dir);

    /* nothing to do if the legacy path doesn't exist */
    if (!path || !ecore_file_exists(path))
    {
        eina_stringshare_del(path);
        return NULL;
    }

    legacy_internal = efreet_menu_internal_new(parent);
    if (!legacy_internal)
        return NULL;
    legacy_internal->name.internal = eina_stringshare_add(ecore_file_file_get(path));

    /* add the legacy dir as an app dir */
    app_dir = efreet_menu_app_dir_new();
    app_dir->path = eina_stringshare_add(path);
    app_dir->legacy = 1;
    if (prefix && !strchr(prefix, '/')) app_dir->prefix = eina_stringshare_add(prefix);

    efreet_menu_create_app_dirs_list(legacy_internal);
    legacy_internal->app_dirs = eina_list_append(legacy_internal->app_dirs, app_dir);
#ifndef STRICT_SPEC
    if (root)
    {
        /* XXX This seems wrong, but it makes efreet pass the fdo tests */
        app_dir = efreet_menu_app_dir_new();
        app_dir->path = eina_stringshare_add(path);
        app_dir->legacy = 1;
        if (prefix && !strchr(prefix, '/')) app_dir->prefix = eina_stringshare_add(prefix);
        root->app_dirs = eina_list_append(root->app_dirs, app_dir);
    }
#endif

    /* add the legacy dir as a directory dir */
    efreet_menu_create_directory_dirs_list(legacy_internal);
    legacy_internal->directory_dirs = eina_list_append(legacy_internal->directory_dirs, eina_stringshare_add(path));

    /* setup a filter for all the conforming .desktop files in the legacy
     * dir */
    filter = efreet_menu_filter_new();
    if (!filter)
    {
        efreet_menu_internal_free(legacy_internal);
        return NULL;
    }
    filter->type = EFREET_MENU_FILTER_INCLUDE;

    filter->op->type = EFREET_MENU_FILTER_OP_OR;

    efreet_menu_create_filter_list(legacy_inter